更改变更语言提示

This commit is contained in:
锦恢 2024-12-22 19:30:36 +08:00
parent 23299abd3c
commit d1ab16c5d2
16 changed files with 1654 additions and 78 deletions

View File

@ -1,6 +1,7 @@
<template>
<!-- 渲染区域 -->
<Render></Render>
<!-- <Render></Render> -->
<div id="netlist"></div>
<!-- 右侧工具合集 -->
<RightNav></RightNav>
</template>
@ -13,6 +14,8 @@ import { onMounted } from 'vue';
import { setDefaultCss } from './hook/css';
import { NetlistRender } from './hook/render';
import * as d3 from 'd3';
const { t } = useI18n();
onMounted(async () => {
@ -25,7 +28,9 @@ onMounted(async () => {
// TODO: size
const render = new NetlistRender(netJson, 800, 1000);
const layout = await render.createLayout();
await render.render(layout);
const svg = await render.render(layout, '#netlist');
console.log(svg);
});
</script>

View File

@ -13,4 +13,9 @@ defineComponent({ name: 'netlist-render' });
</script>
<style>
#netlist {
height: 100vh;
width: calc(100vw - var(--right-nav-width));
overflow: hidden;
}
</style>

View File

@ -29,7 +29,7 @@
:title="t('tips')"
width="500"
>
<span>{{ t('setting.language.change-dialog') }}</span>
<span>{{ t('setting.language.change-dialog', [currentLanguage]) }}</span>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="confirmLanguageDialog()">
@ -62,13 +62,16 @@ watch(
}
);
const currentLanguage = ref('简体中文');
const languageDialogShow = ref(false);
function confirmLanguageDialog() {
languageDialogShow.value = false;
}
function onlanguagechange() {
function onlanguagechange(code) {
const option = languageSetting.options.find(item => item.value === code);
currentLanguage.value = option.text;
languageDialogShow.value = true;
}

View File

@ -1,8 +1,8 @@
/**
* @typedef YosysRawNet
* @property {string} creator - JSON 的创建者信息通常是 Yosys 的版本和构建详情
* @property {Record<string, YosysNetModule>} modules - 模块名称到模块定义的映射
* @property {Record<string, YosysModel>} [models] - 模型定义的映射仅在使用 `-aig` 选项时存在
* @property {string} creator JSON 的创建者信息通常是 Yosys 的版本和构建详情
* @property {Record<string, YosysNetModule>} modules 模块名称到模块定义的映射
* @property {Record<string, YosysModel>} [models] 模型定义的映射仅在使用 `-aig` 选项时存在
*/
/**
@ -19,11 +19,11 @@
/**
* @typedef YosysNetModule
* @property {ModuleAttribute} attributes - 模块的属性如是否为顶层模块及其源文件
* @property {Record<string, ParameterValue>} [parameter_default_values] - 参数的默认值
* @property {Record<string, YosysPort>} ports - 端口名称到端口定义的映射
* @property {Record<string, YosysCell>} cells - 单元名称到单元定义的映射
* @property {Record<string, YosysMemory>} [memories] - 内存名称到内存定义的映射
* @property {ModuleAttribute} attributes 模块的属性如是否为顶层模块及其源文件
* @property {Record<string, ParameterValue>} [parameter_default_values] 参数的默认值
* @property {Record<string, YosysPort>} ports 端口名称到端口定义的映射
* @property {Record<string, YosysCell>} cells 单元名称到单元定义的映射
* @property {Record<string, YosysMemory>} [memories] 内存名称到内存定义的映射
* @property {Record<string, YosysNetname>} netnames 信号名称到网络定义的映射
*
* 信号名称大体分为两种
@ -81,68 +81,68 @@
/**
* @typedef YosysPort 描述一个 module port
* @property {PortDirection} direction - 端口的方向例如 "input""output" "inout"
* @property {WireId[]} bits - 当前 port 每一个位置 bit 的信号 ID. bits.length
* @property {number} [offset] - 使用的最低位索引如果非 0
* @property {number} [upto] - 如果端口位索引是 MSB-first则为 1
* @property {number} [signed] - 如果端口是有符号的则为 1
* @property {PortDirection} direction 端口的方向例如 "input""output" "inout"
* @property {WireId[]} bits 当前 port 每一个位置 bit 的信号 ID. bits.length
* @property {number} [offset] 使用的最低位索引如果非 0
* @property {number} [upto] 如果端口位索引是 MSB-first则为 1
* @property {number} [signed] 如果端口是有符号的则为 1
*/
/**
* @typedef YosysCell 描述一个基本器件
* @property {number} hide_name - 当前器件是否有具体的名字如果有则为 1否则为 0 加减乘除都是无名器件一般都为 0例化模块都是有名字的一般都为 1
* @property {string} type - 器件的类型例如 "$_AND_" 代表 yosys 内置的与门 full_adder_1bit 代表当前器件是一个单位全加器的例化模块
* @property {string} [model] - AIG 模型名称仅在使用 `-aig` 选项时存在
* @property {Record<string, string>} [parameters] - 与单元关联的参数如果有
* @property {CellAttribute} attributes - 单元的属性如源文件和行号
* @property {Record<string, PortDirection>} port_directions - 端口名称到端口方向的映射例如 "input""output" "inout"
* @property {Record<string, WireId[]>} connections - 端口名称到 信号ID 的映射
* @property {number} hide_name 当前器件是否有具体的名字如果有则为 1否则为 0 加减乘除都是无名器件一般都为 0例化模块都是有名字的一般都为 1
* @property {string} type 器件的类型例如 "$_AND_" 代表 yosys 内置的与门 full_adder_1bit 代表当前器件是一个单位全加器的例化模块
* @property {string} [model] AIG 模型名称仅在使用 `-aig` 选项时存在
* @property {Record<string, string>} [parameters] 与单元关联的参数如果有
* @property {CellAttribute} attributes 单元的属性如源文件和行号
* @property {Record<string, PortDirection>} port_directions 端口名称到端口方向的映射例如 "input""output" "inout"
* @property {Record<string, WireId[]>} connections 端口名称到 信号ID 的映射
*/
/**
* @typedef CellAttribute
* @property {string} src - 单元定义的源文件和行号
* @property {string} src 单元定义的源文件和行号
*/
/**
* @typedef YosysMemory
* @property {number} hide_name - 是否隐藏内存名称1 表示是0 表示否
* @property {Record<string, any>} attributes - 内存的属性
* @property {number} width - 内存的宽度
* @property {number} start_offset - 最低有效内存地址
* @property {number} size - 内存的大小
* @property {number} hide_name 是否隐藏内存名称1 表示是0 表示否
* @property {Record<string, any>} attributes 内存的属性
* @property {number} width 内存的宽度
* @property {number} start_offset 最低有效内存地址
* @property {number} size 内存的大小
*/
/**
* @typedef YosysNetname 一个模块内部的所有变量port临时变量等等
* @property {number} hide_name - 同上
* @property {WireId[]} bits - 与网络名称关联的位索引
* @property {number} [offset] - 使用的最低位索引如果非 0
* @property {number} [upto] - 如果端口位索引是 MSB-first则为 1
* @property {number} [signed] - 如果端口是有符号的则为 1
* @property {number} hide_name 同上
* @property {WireId[]} bits 与网络名称关联的位索引
* @property {number} [offset] 使用的最低位索引如果非 0
* @property {number} [upto] 如果端口位索引是 MSB-first则为 1
* @property {number} [signed] 如果端口是有符号的则为 1
*/
/**
* @typedef YosysModel
* @property {Array<Array<any>>} [model_name] - AIG 模型的节点列表
* @property {Array<Array<any>>} [model_name] AIG 模型的节点列表
*/
/**
* @typedef YosysAIGNode
* @property {string} type - 节点类型例如 "port""nport""and""nand""true""false"
* @property {string} [portname] - 端口名称如果节点类型为 "port" "nport"
* @property {number} [bitindex] - 位索引如果节点类型为 "port" "nport"
* @property {number} [node_index] - 节点索引如果节点类型为 "and" "nand"
* @property {Array<string>} [out_list] - 输出端口名称和位索引的列表
* @property {string} type 节点类型例如 "port""nport""and""nand""true""false"
* @property {string} [portname] 端口名称如果节点类型为 "port" "nport"
* @property {number} [bitindex] 位索引如果节点类型为 "port" "nport"
* @property {number} [node_index] 节点索引如果节点类型为 "and" "nand"
* @property {Array<string>} [out_list] 输出端口名称和位索引的列表
*/
/**
* @typedef ElkGraph
* @property {string} id - 图形的唯一标识符
* @property {ElkNode[]} children - 图形的子节点列表
* @property {ElkEdge[]} edges - 图形中的边列表
* @property {ElkLayoutOptions} [layoutOptions] - 图形的布局选项可选
* @property {string} id 图形的唯一标识符
* @property {ElkNode[]} children 图形的子节点列表
* @property {ElkEdge[]} edges 图形中的边列表
* @property {ElkLayoutOptions} [layoutOptions] 图形的布局选项可选
*/
/**
@ -152,30 +152,47 @@
* @property {ElkPort[]} ports 当前节点的端口
* @property {ElkEdge[]} edges 当前节点的连线
* @property {string} type 节点的类型
* @property {number} [x] - 节点的 X 坐标可选由布局算法生成
* @property {number} [y] - 节点的 Y 坐标可选由布局算法生成
* @property {number} [width] - 节点的宽度可选
* @property {number} [height] - 节点的高度可选
* @property {ElkPort[]} [ports] - 节点的端口列表可选
* @property {ElkLayoutOptions} [layoutOptions] - 节点的布局选项可选
* @property {number} [x] 节点的 X 坐标可选由布局算法生成
* @property {number} [y] 节点的 Y 坐标可选由布局算法生成
* @property {number} [width] 节点的宽度可选
* @property {number} [height] 节点的高度可选
* @property {ElkPort[]} [ports] 节点的端口列表可选
* @property {ElkLayoutOptions} [layoutOptions] 节点的布局选项可选
*/
/**
* @typedef ElkPort
* @property {string} id - 端口的唯一标识符
* @property {number} [x] - 端口的 X 坐标可选由布局算法生成
* @property {number} [y] - 端口的 Y 坐标可选由布局算法生成
* @property {number} [width] - 端口的宽度可选
* @property {number} [height] - 端口的高度可选
* @property {ElkLayoutOptions} [layoutOptions] - 端口的布局选项可选
* @property {string} id 端口的唯一标识符
* @property {number} [x] 端口的 X 坐标可选由布局算法生成
* @property {number} [y] 端口的 Y 坐标可选由布局算法生成
* @property {number} [width] 端口的宽度可选
* @property {number} [height] 端口的高度可选
* @property {ElkLayoutOptions} [layoutOptions] 端口的布局选项可选
*/
/**
* @typedef ElkEdge
* @property {string} id - 边的唯一标识符
* @property {string[]} sources - 边的源节点列表
* @property {string[]} targets - 边的目标节点列表
* @property {ElkLayoutOptions} [layoutOptions] - 边的布局选项可选
* @property {string} id 边的唯一标识符
* @property {string[]} sources 边的源节点列表
* @property {string[]} targets 边的目标节点列表
* @property {string} [container] 所在容器的 id 可选由布局算法生成
* @property {ElkSection[]} [sections] 具体的连线规则可选由布局算法生成
* @property {ElkLayoutOptions} [layoutOptions] 边的布局选项可选
*/
/**
* @typedef ElkPoint
* @property {number} x
* @property {number} y
*/
/**
* @typedef ElkSection
* @property {ElkPoint} startPoint
* @property {ElkPoint} endPoint
* @property {string} id edge id
* @property {string} incomingShape source 实体的 id
* @property {string} outgoingShape target 实体的 id
*/
/**
@ -185,4 +202,5 @@
* @property {number} [elk.spacing.nodeNode] - 节点之间的间距可选
* @property {number} [elk.spacing.edgeNode] - 边与节点之间的间距可选
* @property {'NORTH' | 'SOUTH' | 'EAST' | 'WEST'} [elk.port.side] - 端口的位置可选 "NORTH", "SOUTH", "EAST", "WEST"
*/
*/

View File

@ -67,9 +67,12 @@ export class NetlistRender {
* @returns {Promise<ElkNode>}
*/
async createLayout() {
const elk = new ELK();
const elk = new ELK({
// 分层算法,使得生成的边和坐标轴平行
algorithm: 'layered'
});
const graph = this.elkGraph;
const layoutGraph = await elk.layout(graph, {});
const layoutGraph = await elk.layout(graph);
console.log(layoutGraph);
return layoutGraph;
@ -78,8 +81,10 @@ export class NetlistRender {
/**
*
* @param {ElkNode} computedLayout
* @param {string} container 类似于 "#chart"
* @returns {d3.Selection}
*/
async render(computedLayout) {
async render(computedLayout, container) {
const virtualHeight = computedLayout.height;
const virtualWidth = computedLayout.width;
@ -87,7 +92,94 @@ export class NetlistRender {
const ratio = this.renderHeight / virtualHeight;
// 遍历计算布局进行创建
const svg = d3.select(container).append('svg')
.attr('width', this.renderWidth)
.attr('height', this.renderHeight);
await this.renderEntity(svg, computedLayout, ratio);
await this.renderLine(svg, computedLayout, ratio);
return svg;
}
/**
* @description 绘制实体
* @param {d3.Selection} svg
* @param {ElkNode} computedLayout
* @param {number} ratio
*/
async renderEntity(svg, computedLayout, ratio) {
// node 可能是如下的几类
// - module 的 port
// - 器件(基础器件 & 例化模块)
// - 器件的 port
// 生成用于绘制的 d3 数据结构
const squares = [];
for (const node of computedLayout.children) {
squares.push({
x: node.x,
y: node.y,
width: node.width,
height: node.height,
fill: 'green'
});
// 如果存在 port绘制 port
for (const cellPort of node.ports || []) {
squares.push({
x: cellPort.x + node.x,
y: cellPort.y + node.y,
width: cellPort.width,
height: cellPort.height,
fill: 'blue'
});
}
}
svg.selectAll('rect')
.data(squares)
.enter()
.append('rect')
.attr('x', data => data.x)
.attr('y', data => data.y)
.attr('width', data => data.width)
.attr('height', data => data.height)
.attr('fill', d => d.fill)
.attr('stroke', 'white')
.attr('stroke-width', 2);
}
/**
* @description 绘制连线
* @param {d3.Selection} svg
* @param {ElkNode} computedLayout
* @param {number} ratio
*/
async renderLine(svg, computedLayout, ratio) {
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'
});
}
}
svg.selectAll('line')
.data(lines)
.enter()
.append('line')
.attr('x1', data => data.x1)
.attr('y1', data => data.y1)
.attr('x2', data => data.x2)
.attr('y2', data => data.y2)
.attr('stroke-width', data => data.strokeWidth)
.attr('stroke', data => data.color)
}
}

View File

@ -106,8 +106,7 @@ export class Module {
width: LAYOUT_CONSTANT.CELL_PORT_WIDTH,
height: LAYOUT_CONSTANT.CELL_PORT_HEIGHT,
properties: {
'port.side': portSide,
'allowNonFlowPortsToSwitchSides': true
'port.side': portSide
}
})
}
@ -116,7 +115,11 @@ export class Module {
id: cell.id,
width,
height,
ports
ports,
properties: {
// 强制固定 port 的方向
'portConstraints': 'FIXED_ORDER'
},
}
nodes.push(node);

View File

@ -8,5 +8,5 @@
"cancel": "إلغاء",
"tips": "نصائح",
"language-setting": "اللغة",
"setting.language.change-dialog": "لقد قمت بتغيير اللغة إلى الصينية المبسطة، نوصي بإعادة تشغيل Netlist Viewer"
"setting.language.change-dialog": "لقد قمت بتغيير اللغة إلى {0} ، ونوصي بإعادة تشغيل Netlist Viewer"
}

View File

@ -8,5 +8,5 @@
"cancel": "Abbrechen",
"tips": "Tipps",
"language-setting": "Sprache",
"setting.language.change-dialog": "Sie haben die Sprache auf Chinesisch (vereinfacht) geändert, wir empfehlen Ihnen, Netlist Viewer neu zu starten"
"setting.language.change-dialog": "Sie haben die Sprache auf {0} geändert. Wir empfehlen Ihnen, Netlist Viewer neu zu starten."
}

View File

@ -3,10 +3,10 @@
"general-setting": "General",
"appearance-setting": "Appearance",
"current-version": "current version",
"copyright": "The copyright of this software belongs to <a href=\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"https://github.com/Digital-EDA\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\" target=\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"_blank\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\">Digital-IDE</a> project team. Welcome to <a href=\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"https://github.com/Digital-EDA/Digital-IDE\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\">Star</a>.",
"copyright": "The copyright of this software belongs to <a href=\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"https://github.com/Digital-EDA\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\" target=\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"_blank\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\">Digital-IDE</a> project team. Welcome to <a href=\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"https://github.com/Digital-EDA/Digital-IDE\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\">Star</a>.",
"confirm": "confirm",
"cancel": "cancel",
"tips": "Tips",
"language-setting": "Language",
"setting.language.change-dialog": "You've switched language to English, we recommend you reload Netlist Viewer"
"setting.language.change-dialog": "You have changed the language to {0}, we recommend restarting Netlist Viewer."
}

View File

@ -8,5 +8,5 @@
"cancel": "Annuler",
"tips": "Conseils",
"language-setting": "Langue",
"setting.language.change-dialog": "Vous avez changé la langue en chinois simplifié, nous vous recommandons de redémarrer Netlist Viewer"
"setting.language.change-dialog": "Vous avez changé la langue en {0}, nous vous recommandons de redémarrer Netlist Viewer."
}

View File

@ -8,5 +8,5 @@
"cancel": "キャンセル",
"tips": "ヒント",
"language-setting": "言語",
"setting.language.change-dialog": "言語を簡体字中国語に変更しました。Netlist Viewerを再起動することをお勧めします。"
"setting.language.change-dialog": "言語を {0} に変更しました。Netlist Viewer を再起動することをお勧めします。"
}

View File

@ -8,5 +8,5 @@
"cancel": "취소",
"tips": "팁",
"language-setting": "언어",
"setting.language.change-dialog": "언어를 중국어 간체로 변경했습니다. Netlist Viewer를 다시 시작하는 것이 좋습니다."
"setting.language.change-dialog": "언어를 {0} 으로 변경했습니다. Netlist Viewer 를 다시 시작하는 것을 권장합니다."
}

View File

@ -8,5 +8,5 @@
"cancel": "Отменить",
"tips": "Советы",
"language-setting": "Язык",
"setting.language.change-dialog": "Вы изменили язык на упрощенный китайский, мы рекомендуем вам перезапустить Netlist Viewer"
"setting.language.change-dialog": "Вы изменили язык на {0}, мы рекомендуем перезапустить Netlist Viewer."
}

View File

@ -8,5 +8,5 @@
"cancel": "取消",
"tips": "提示",
"language-setting": "语言",
"setting.language.change-dialog": "您已经更换语言为简体中文,我们建议您重启 Netlist Viewer"
"setting.language.change-dialog": "您已经更换语言为 {0} ,我们建议您重启 Netlist Viewer"
}

View File

@ -8,5 +8,5 @@
"cancel": "取消",
"tips": "提示",
"language-setting": "語言",
"setting.language.change-dialog": "您已經更換語言為簡體中文,我們建議您重啟 Netlist Viewer"
"setting.language.change-dialog": "您已將語言更改為 {0} ,我們建議您重新啟動 Netlist Viewer。"
}

1450
src/static/dn-0.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 651 KiB