更新布局
This commit is contained in:
parent
0ffc2dc0e5
commit
6e4615a236
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
window.readNetFile = async () => {
|
window.readNetFile = async () => {
|
||||||
const inputVcdFile = 'test.json';
|
const inputVcdFile = 'full_adder.json';
|
||||||
const skin = 'test.skin';
|
const skin = 'test.skin';
|
||||||
const r1 = await fetch(inputVcdFile);
|
const r1 = await fetch(inputVcdFile);
|
||||||
const r2 = await fetch(skin);
|
const r2 = await fetch(skin);
|
||||||
@ -23,7 +23,7 @@
|
|||||||
const skinBinary = await r2.arrayBuffer();
|
const skinBinary = await r2.arrayBuffer();
|
||||||
return [ netJson, skinBinary ];
|
return [ netJson, skinBinary ];
|
||||||
}
|
}
|
||||||
window.moduleName = 'half_adder';
|
window.moduleName = 'full_adder';
|
||||||
// window.avoidWasm = 'avoid.wasm';
|
// window.avoidWasm = 'avoid.wasm';
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
@ -4,9 +4,11 @@
|
|||||||
<div class="setting-section">
|
<div class="setting-section">
|
||||||
<h2>{{ t('general-setting') }}</h2>
|
<h2>{{ t('general-setting') }}</h2>
|
||||||
<div class="setting-option" style="width: 220px;">
|
<div class="setting-option" style="width: 220px;">
|
||||||
<span class="iconfont icon-i18n"></span>
|
<span>
|
||||||
 
|
<span class="iconfont icon-i18n"></span>
|
||||||
<span class="option-title">{{ t('language-setting') }}</span>
|
 
|
||||||
|
<span class="option-title">{{ t('language-setting') }}</span>
|
||||||
|
</span>
|
||||||
<div style="width: 100px;">
|
<div style="width: 100px;">
|
||||||
<el-select
|
<el-select
|
||||||
name="language-setting"
|
name="language-setting"
|
||||||
@ -151,23 +153,35 @@ const languageSetting = reactive({
|
|||||||
}
|
}
|
||||||
|
|
||||||
.setting-option {
|
.setting-option {
|
||||||
margin: 5px;
|
margin: 3px;
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
width: fit-content;
|
width: 280px !important;
|
||||||
border-radius: .5em;
|
border-radius: .5em;
|
||||||
background-color: var(--background);
|
background-color: var(--background);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.option-group {
|
||||||
|
display: flex;
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
|
||||||
.option-title {
|
.option-title {
|
||||||
|
font-size: 0.8rem;
|
||||||
min-width: 80px;
|
min-width: 80px;
|
||||||
margin-right: 12px;
|
margin-right: 12px;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-checkbox-button.is-checked:first-child .el-checkbox-button__inner,
|
||||||
|
.el-checkbox-button__inner {
|
||||||
|
font-size: 0.8rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
.el-slider__button {
|
.el-slider__button {
|
||||||
background-color: var(--background) !important;
|
background-color: var(--background) !important;
|
||||||
}
|
}
|
||||||
|
@ -151,7 +151,7 @@ import { Module } from "./render/layout";
|
|||||||
* @typedef ElkNode
|
* @typedef ElkNode
|
||||||
* @property {string} id 节点的唯一标识符。
|
* @property {string} id 节点的唯一标识符。
|
||||||
* @property {string} [renderName] node 展示的名字,布局算法前生成
|
* @property {string} [renderName] node 展示的名字,布局算法前生成
|
||||||
* @property {'port' | 'cell' | 'cellPort'} [renderType] 渲染的类型
|
* @property {'port' | 'cell' | 'cellPort' | 'portConnection'} [renderType] 渲染的类型
|
||||||
* @property {ElkNode[]} children 当前节点的内部
|
* @property {ElkNode[]} children 当前节点的内部
|
||||||
* @property {ElkPort[]} ports 当前节点的端口
|
* @property {ElkPort[]} ports 当前节点的端口
|
||||||
* @property {ElkEdge[]} edges 当前节点的连线
|
* @property {ElkEdge[]} edges 当前节点的连线
|
||||||
|
@ -30,10 +30,19 @@ export class NetlistRender {
|
|||||||
layoutOptions: {
|
layoutOptions: {
|
||||||
// org.eclipse. 可以去除
|
// org.eclipse. 可以去除
|
||||||
'org.eclipse.elk.layered.spacing.nodeNodeBetweenLayers': 35,
|
'org.eclipse.elk.layered.spacing.nodeNodeBetweenLayers': 35,
|
||||||
|
// node 之间的最小间距
|
||||||
'elk.spacing.nodeNode': 35,
|
'elk.spacing.nodeNode': 35,
|
||||||
'elk.layered.layering.strategy': 'NETWORK_SIMPLEX',
|
// layered 算法布局,尽可能让全体布局从左向右
|
||||||
'elk.algorithm': 'layered',
|
'elk.algorithm': 'layered',
|
||||||
|
// layered 算法的风格
|
||||||
|
'elk.layered.layering.strategy': 'NETWORK_SIMPLEX',
|
||||||
|
// ...
|
||||||
|
'elk.layered.considerModelOrder.longEdgeStrategy': 'DUMMY_NODE_UNDER',
|
||||||
|
// edge 的生成采用正交路由算法
|
||||||
|
'elk.edgeRouting': 'ORTHOGONAL',
|
||||||
|
// 指定 layered 算法的方向为从左到右
|
||||||
'elk.direction': 'RIGHT',
|
'elk.direction': 'RIGHT',
|
||||||
|
// 激活 node 分区功能,可以通过 partitioning.partition 赋予 id 的方式给 node 进行分组
|
||||||
'elk.partitioning.activate': true
|
'elk.partitioning.activate': true
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -259,8 +268,7 @@ export class NetlistRender {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.portRender.render();
|
this.portRender.render();
|
||||||
// TODO: 实现它
|
this.instantiationRender.render();
|
||||||
// this.instantiationRender.render();
|
|
||||||
this.cellRender.render();
|
this.cellRender.render();
|
||||||
this.connectionRender.render();
|
this.connectionRender.render();
|
||||||
}
|
}
|
||||||
@ -394,7 +402,7 @@ export class NetlistRender {
|
|||||||
connections: []
|
connections: []
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// id 代表 cell, portId 代表 connection
|
// id 代表 cell, portId 代表 connection
|
||||||
const cellManager = id2manager.get(id)[0];
|
const cellManager = id2manager.get(id)[0];
|
||||||
const connectionManager = id2manager.get(portId)[0];
|
const connectionManager = id2manager.get(portId)[0];
|
||||||
return {
|
return {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import * as d3 from 'd3';
|
import * as d3 from 'd3';
|
||||||
import { NetlistRender } from '.';
|
import { NetlistRender } from '.';
|
||||||
|
import { globalSetting } from '../global';
|
||||||
|
|
||||||
export class InstantiationRender {
|
export class InstantiationRender {
|
||||||
/**
|
/**
|
||||||
@ -8,7 +9,7 @@ export class InstantiationRender {
|
|||||||
* @param {NetlistRender} rootRender
|
* @param {NetlistRender} rootRender
|
||||||
*/
|
*/
|
||||||
constructor(selection, rootRender) {
|
constructor(selection, rootRender) {
|
||||||
this.selection = selection;
|
this.parentSelection = selection;
|
||||||
this.rootRender = rootRender;
|
this.rootRender = rootRender;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -27,8 +28,9 @@ export class InstantiationRender {
|
|||||||
* @description 将 elknode 关于 例化模块 的数据添加为 d3 数据项目
|
* @description 将 elknode 关于 例化模块 的数据添加为 d3 数据项目
|
||||||
* @param {ElkNode} node
|
* @param {ElkNode} node
|
||||||
*/
|
*/
|
||||||
addAsD3DataItem(node) {
|
addAsD3DataItem(node) {
|
||||||
this.data.push({
|
this.data.push({
|
||||||
|
id: node.id,
|
||||||
x: node.x,
|
x: node.x,
|
||||||
y: node.y,
|
y: node.y,
|
||||||
name: node.name,
|
name: node.name,
|
||||||
@ -72,7 +74,7 @@ export class InstantiationRender {
|
|||||||
.attr('class', 'port-caption')
|
.attr('class', 'port-caption')
|
||||||
.text(data => data.name); // 设置文本内容
|
.text(data => data.name); // 设置文本内容
|
||||||
|
|
||||||
|
|
||||||
if (globalSetting.renderAnimation) {
|
if (globalSetting.renderAnimation) {
|
||||||
instances.transition()
|
instances.transition()
|
||||||
.duration(1000)
|
.duration(1000)
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { globalLookup } from "../global";
|
import { globalLookup } from "../global";
|
||||||
import { Cell, ModuleView } from "./yosys";
|
import { Cell, dotConnect, ModuleView } from "./yosys";
|
||||||
|
|
||||||
export const LINE_WIDTH = 2;
|
export const LINE_WIDTH = 2;
|
||||||
|
|
||||||
@ -13,8 +13,11 @@ export const LAYOUT_CONSTANT = {
|
|||||||
PORT_HEIGHT: 20,
|
PORT_HEIGHT: 20,
|
||||||
|
|
||||||
// 例化模块(这只是最小,height 会根据端口数量进行调整)
|
// 例化模块(这只是最小,height 会根据端口数量进行调整)
|
||||||
INSTANTIATION_WIDTH: 50,
|
INSTANTIATION_WIDTH: 80,
|
||||||
INSTANTIATION_HEIGHT: 50,
|
INSTANTIATION_HEIGHT: 80,
|
||||||
|
|
||||||
|
// port 顶部的空余,一般用来放置标签的
|
||||||
|
PORT_TOP_MARGIN: 30,
|
||||||
|
|
||||||
// 常数
|
// 常数
|
||||||
CONSTANT_WIDTH: 50,
|
CONSTANT_WIDTH: 50,
|
||||||
@ -64,7 +67,18 @@ export class Module {
|
|||||||
for (const name of this.view.nameToPort.keys()) {
|
for (const name of this.view.nameToPort.keys()) {
|
||||||
const port = this.view.nameToPort.get(name);
|
const port = this.view.nameToPort.get(name);
|
||||||
|
|
||||||
|
|
||||||
if (port.direction === 'input') {
|
if (port.direction === 'input') {
|
||||||
|
// 为 port 设置连接点
|
||||||
|
const portConnection = {
|
||||||
|
id: dotConnect(port.id, '0'),
|
||||||
|
renderType: 'portConnection',
|
||||||
|
width: 1,
|
||||||
|
height: 1,
|
||||||
|
x: LAYOUT_CONSTANT.PORT_WIDTH,
|
||||||
|
y: LAYOUT_CONSTANT.PORT_HEIGHT / 2
|
||||||
|
};
|
||||||
|
|
||||||
const node = {
|
const node = {
|
||||||
id: port.id,
|
id: port.id,
|
||||||
name: port.name,
|
name: port.name,
|
||||||
@ -73,13 +87,25 @@ export class Module {
|
|||||||
type: port.direction,
|
type: port.direction,
|
||||||
width: LAYOUT_CONSTANT.PORT_WIDTH,
|
width: LAYOUT_CONSTANT.PORT_WIDTH,
|
||||||
height: LAYOUT_CONSTANT.PORT_HEIGHT,
|
height: LAYOUT_CONSTANT.PORT_HEIGHT,
|
||||||
|
ports: [portConnection],
|
||||||
layoutOptions: {
|
layoutOptions: {
|
||||||
'partitioning.partition': 1
|
'partitioning.partition': 1,
|
||||||
|
'org.eclipse.elk.portConstraints': 'FIXED_POS'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
nodes.push(node);
|
nodes.push(node);
|
||||||
} else {
|
} else {
|
||||||
|
// 为 port 设置连接点
|
||||||
|
const portConnection = {
|
||||||
|
id: dotConnect(port.id, '0'),
|
||||||
|
renderType: 'portConnection',
|
||||||
|
width: 1,
|
||||||
|
height: 1,
|
||||||
|
x: 0,
|
||||||
|
y: LAYOUT_CONSTANT.PORT_HEIGHT / 2
|
||||||
|
};
|
||||||
|
|
||||||
const node = {
|
const node = {
|
||||||
id: port.id,
|
id: port.id,
|
||||||
name: port.name,
|
name: port.name,
|
||||||
@ -88,8 +114,10 @@ export class Module {
|
|||||||
type: port.direction,
|
type: port.direction,
|
||||||
width: LAYOUT_CONSTANT.PORT_WIDTH,
|
width: LAYOUT_CONSTANT.PORT_WIDTH,
|
||||||
height: LAYOUT_CONSTANT.PORT_HEIGHT,
|
height: LAYOUT_CONSTANT.PORT_HEIGHT,
|
||||||
|
ports: [portConnection],
|
||||||
layoutOptions: {
|
layoutOptions: {
|
||||||
'partitioning.partition': 999
|
'partitioning.partition': 999,
|
||||||
|
'org.eclipse.elk.portConstraints': 'FIXED_POS'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -191,9 +219,8 @@ export class Module {
|
|||||||
// 例化模块
|
// 例化模块
|
||||||
|
|
||||||
// 创建器件节点的 port, port 和 connection 一一对应
|
// 创建器件节点的 port, port 和 connection 一一对应
|
||||||
const ports = [];
|
const ports = [];
|
||||||
|
for (const connectionName of cell.nameToConnection.keys()) {
|
||||||
for (const connectionName of cell.nameToConnection.keys()) {
|
|
||||||
const connection = cell.nameToConnection.get(connectionName);
|
const connection = cell.nameToConnection.get(connectionName);
|
||||||
const portSide = connection.direction === 'input' ? ELK_DIRECTION.LEFT: ELK_DIRECTION.RIGHT;
|
const portSide = connection.direction === 'input' ? ELK_DIRECTION.LEFT: ELK_DIRECTION.RIGHT;
|
||||||
ports.push({
|
ports.push({
|
||||||
@ -202,9 +229,9 @@ export class Module {
|
|||||||
renderType: 'cellPort',
|
renderType: 'cellPort',
|
||||||
width: LAYOUT_CONSTANT.CELL_PORT_WIDTH,
|
width: LAYOUT_CONSTANT.CELL_PORT_WIDTH,
|
||||||
height: LAYOUT_CONSTANT.CELL_PORT_HEIGHT,
|
height: LAYOUT_CONSTANT.CELL_PORT_HEIGHT,
|
||||||
// properties: {
|
properties: {
|
||||||
// 'port.side': portSide
|
'port.side': portSide
|
||||||
// }
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,8 +240,8 @@ export class Module {
|
|||||||
name: cell.name,
|
name: cell.name,
|
||||||
renderName: cell.type,
|
renderName: cell.type,
|
||||||
renderType: 'cell',
|
renderType: 'cell',
|
||||||
width,
|
width: LAYOUT_CONSTANT.INSTANTIATION_WIDTH,
|
||||||
height,
|
height: LAYOUT_CONSTANT.INSTANTIATION_HEIGHT,
|
||||||
ports,
|
ports,
|
||||||
layoutOptions: {
|
layoutOptions: {
|
||||||
// 强制固定 port 的方向
|
// 强制固定 port 的方向
|
||||||
@ -289,23 +316,22 @@ export class Module {
|
|||||||
if (port.direction === 'input') {
|
if (port.direction === 'input') {
|
||||||
const edge = {
|
const edge = {
|
||||||
// id 遵循 sourcePort-targetPort
|
// id 遵循 sourcePort-targetPort
|
||||||
id: makeEdgeId(port.id, cell.id),
|
id: makeEdgeId(port.id, connection.id),
|
||||||
source: port.id,
|
source: port.id,
|
||||||
sourcePort: port.id,
|
sourcePort: dotConnect(port.id, '0'),
|
||||||
target: cell.id,
|
target: cell.id,
|
||||||
targetPort: connection.id
|
targetPort: connection.id
|
||||||
};
|
};
|
||||||
|
|
||||||
edges.push(edge);
|
edges.push(edge);
|
||||||
} else {
|
} else {
|
||||||
const edge = {
|
const edge = {
|
||||||
id: makeEdgeId(cell.id, port.id),
|
id: makeEdgeId(connection.id, port.id),
|
||||||
source: cell.id,
|
source: cell.id,
|
||||||
sourcePort: connection.id,
|
sourcePort: connection.id,
|
||||||
target: port.id,
|
target: port.id,
|
||||||
targetPort: port.id
|
targetPort: dotConnect(port.id, '0')
|
||||||
};
|
};
|
||||||
|
|
||||||
edges.push(edge);
|
edges.push(edge);
|
||||||
}
|
}
|
||||||
} else if (tree.wireIdToConnection.has(wireId)) {
|
} else if (tree.wireIdToConnection.has(wireId)) {
|
||||||
@ -313,10 +339,15 @@ export class Module {
|
|||||||
// 当前的器件的这个端口和另一个器件的一个端口连接
|
// 当前的器件的这个端口和另一个器件的一个端口连接
|
||||||
const conn = tree.wireIdToConnection.get(wireId);
|
const conn = tree.wireIdToConnection.get(wireId);
|
||||||
|
|
||||||
|
// 防止查询到自己
|
||||||
|
if (conn.id === connection.id && conn.cell.id === cell.id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (conn.direction === 'input') {
|
if (conn.direction === 'input') {
|
||||||
const edge = {
|
const edge = {
|
||||||
// id 遵循 sourcePort-targetPort
|
// id 遵循 sourcePort-targetPort
|
||||||
id: makeEdgeId(conn.id, cell.id),
|
id: makeEdgeId(conn.id, connection.id),
|
||||||
source: conn.cell.id,
|
source: conn.cell.id,
|
||||||
sourcePort: conn.id,
|
sourcePort: conn.id,
|
||||||
target: cell.id,
|
target: cell.id,
|
||||||
@ -326,13 +357,12 @@ export class Module {
|
|||||||
edges.push(edge);
|
edges.push(edge);
|
||||||
} else {
|
} else {
|
||||||
const edge = {
|
const edge = {
|
||||||
id: makeEdgeId(cell.id, conn.id),
|
id: makeEdgeId(connection.id, conn.id),
|
||||||
source: cell.id,
|
source: cell.id,
|
||||||
sourcePort: connection.id,
|
sourcePort: connection.id,
|
||||||
target: conn.id,
|
target: conn.cell.id,
|
||||||
targetPort: conn.cell.id
|
targetPort: conn.id
|
||||||
};
|
};
|
||||||
|
|
||||||
edges.push(edge);
|
edges.push(edge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user