更改变更语言提示

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

View File

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

View File

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

View File

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

View File

@ -67,9 +67,12 @@ export class NetlistRender {
* @returns {Promise<ElkNode>} * @returns {Promise<ElkNode>}
*/ */
async createLayout() { async createLayout() {
const elk = new ELK(); const elk = new ELK({
// 分层算法,使得生成的边和坐标轴平行
algorithm: 'layered'
});
const graph = this.elkGraph; const graph = this.elkGraph;
const layoutGraph = await elk.layout(graph, {}); const layoutGraph = await elk.layout(graph);
console.log(layoutGraph); console.log(layoutGraph);
return layoutGraph; return layoutGraph;
@ -78,8 +81,10 @@ export class NetlistRender {
/** /**
* *
* @param {ElkNode} computedLayout * @param {ElkNode} computedLayout
* @param {string} container 类似于 "#chart"
* @returns {d3.Selection}
*/ */
async render(computedLayout) { async render(computedLayout, container) {
const virtualHeight = computedLayout.height; const virtualHeight = computedLayout.height;
const virtualWidth = computedLayout.width; const virtualWidth = computedLayout.width;
@ -87,7 +92,94 @@ export class NetlistRender {
const ratio = this.renderHeight / virtualHeight; 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, 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
'allowNonFlowPortsToSwitchSides': true
} }
}) })
} }
@ -116,7 +115,11 @@ export class Module {
id: cell.id, id: cell.id,
width, width,
height, height,
ports ports,
properties: {
// 强制固定 port 的方向
'portConstraints': 'FIXED_ORDER'
},
} }
nodes.push(node); nodes.push(node);

View File

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

View File

@ -8,5 +8,5 @@
"cancel": "Abbrechen", "cancel": "Abbrechen",
"tips": "Tipps", "tips": "Tipps",
"language-setting": "Sprache", "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", "general-setting": "General",
"appearance-setting": "Appearance", "appearance-setting": "Appearance",
"current-version": "current version", "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", "confirm": "confirm",
"cancel": "cancel", "cancel": "cancel",
"tips": "Tips", "tips": "Tips",
"language-setting": "Language", "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", "cancel": "Annuler",
"tips": "Conseils", "tips": "Conseils",
"language-setting": "Langue", "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": "キャンセル", "cancel": "キャンセル",
"tips": "ヒント", "tips": "ヒント",
"language-setting": "言語", "language-setting": "言語",
"setting.language.change-dialog": "言語を簡体字中国語に変更しました。Netlist Viewerを再起動することをお勧めします。" "setting.language.change-dialog": "言語を {0} に変更しました。Netlist Viewer を再起動することをお勧めします。"
} }

View File

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

View File

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

View File

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

View File

@ -8,5 +8,5 @@
"cancel": "取消", "cancel": "取消",
"tips": "提示", "tips": "提示",
"language-setting": "語言", "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