完成 cell 的最小拓扑图的构造
This commit is contained in:
parent
b718780cf5
commit
b8bbc0e290
@ -1,6 +1,6 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 4440655 */
|
||||
src: url('iconfont.woff2?t=1734508613033') format('woff2');
|
||||
src: url('iconfont.woff2?t=1735201425292') format('woff2');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
@ -11,6 +11,18 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-single-click:before {
|
||||
content: "\e664";
|
||||
}
|
||||
|
||||
.icon-wheel-change:before {
|
||||
content: "\e6ad";
|
||||
}
|
||||
|
||||
.icon-double-click:before {
|
||||
content: "\e6fc";
|
||||
}
|
||||
|
||||
.icon-i18n:before {
|
||||
content: "\e678";
|
||||
}
|
||||
|
Binary file not shown.
@ -1,7 +1,23 @@
|
||||
<template>
|
||||
<div class="about-wrapper">
|
||||
<div class="usermanual">
|
||||
|
||||
<h2>{{ t('usermanual') }}</h2>
|
||||
<div class="usermanual-item">
|
||||
<div><span class="iconfont icon-single-click"/> + <span class="iconfont icon-mouse"/></div>
|
||||
<div>{{ t('usermanual.move-view') }}</div>
|
||||
</div>
|
||||
<div class="usermanual-item">
|
||||
<div><span class="iconfont icon-wheel-change"/></div>
|
||||
<div>{{ t('usermanual.scale-view') }}</div>
|
||||
</div>
|
||||
<div class="usermanual-item">
|
||||
<div><span class="iconfont icon-ctrl"/> + <span class="iconfont icon-wheel-change"/></div>
|
||||
<div>{{ t('usermanual.scale-view') }}+</div>
|
||||
</div>
|
||||
<div class="usermanual-item">
|
||||
<div><span class="iconfont icon-double-click"/></div>
|
||||
<div>{{ t('usermanual.scale-view') }}+</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
@ -176,7 +176,11 @@
|
||||
* @typedef ElkEdge
|
||||
* @property {string} id 边的唯一标识符。
|
||||
* @property {string[]} sources 边的源节点列表。
|
||||
* @property {string} source 边的源节点。
|
||||
* @property {string} sourcePort 边的源节点的port。
|
||||
* @property {string[]} targets 边的目标节点列表。
|
||||
* @property {string} target 边的目标节点。
|
||||
* @property {string} targetPort 边的目标节点的port。
|
||||
* @property {string} [container] 所在容器的 id (可选,由布局算法生成)
|
||||
* @property {ElkSection[]} [sections] 具体的连线规则(可选,由布局算法生成)
|
||||
* @property {ElkLayoutOptions} [layoutOptions] 边的布局选项(可选)。
|
||||
@ -232,5 +236,20 @@
|
||||
|
||||
/**
|
||||
* @typedef DragContext
|
||||
* @property {ElkGraph} elkGraph
|
||||
* @property {ElkGraph} elkGraph 用于更新的最小图
|
||||
* @property {DragNeighbor[]} neighbors 当前 selection 代表的节点的邻居
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef DragNeighbor
|
||||
* @property {'port' | 'cell'} type
|
||||
* @property {'source' | 'target'} location
|
||||
* @property {ElkEdge} edge 构成这个邻居关系的 edge
|
||||
* @property {d3.Selection} selection
|
||||
* @property {DragConnection[]} connections 如果 type 为 port, 则为空
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef DragConnection
|
||||
* @property {d3.Selection} selection
|
||||
*/
|
@ -1,6 +1,7 @@
|
||||
import * as d3 from 'd3';
|
||||
import { globalSetting } from '../global';
|
||||
import { NetlistRender } from '.';
|
||||
import { LAYOUT_CONSTANT, makeEdgeId } from './layout';
|
||||
|
||||
export class CellRender {
|
||||
/**
|
||||
@ -58,6 +59,11 @@ export class CellRender {
|
||||
element.setAttribute('stroke-opacity', 0);
|
||||
}
|
||||
return element;
|
||||
})
|
||||
.each(function (data) {
|
||||
const cellSelection = d3.select(this);
|
||||
const manager = _this.createDataManager(cellSelection, data);
|
||||
registerDragEvent(manager, rootRender);
|
||||
});
|
||||
|
||||
if (globalSetting.renderAnimation) {
|
||||
@ -65,20 +71,10 @@ export class CellRender {
|
||||
.transition()
|
||||
.duration(1000)
|
||||
.attr('stroke-opacity', 1)
|
||||
.attr('class', 'grab')
|
||||
.on('end', function (data) {
|
||||
const cellSelection = d3.select(this);
|
||||
const manager = _this.createDataManager(cellSelection, data);
|
||||
registerDragEvent(manager, rootRender);
|
||||
});
|
||||
.attr('class', 'grab');
|
||||
} else {
|
||||
cellSelections = cellSelections
|
||||
.attr('class', 'grab')
|
||||
.each(function (data) {
|
||||
const cellSelection = d3.select(this);
|
||||
const manager = _this.createDataManager(cellSelection, data);
|
||||
registerDragEvent(manager, rootRender);
|
||||
});
|
||||
.attr('class', 'grab');
|
||||
}
|
||||
|
||||
this.selections = cellSelections;
|
||||
@ -95,6 +91,7 @@ export class CellRender {
|
||||
const id2manager = this.id2manager;
|
||||
// 创建拖拽上下文
|
||||
const dragContext = {
|
||||
neighbors: [],
|
||||
elkGraph: {
|
||||
// elk 是无状态的,id 取什么名字都行
|
||||
id: 'root',
|
||||
@ -114,7 +111,7 @@ export class CellRender {
|
||||
id2manager.set(data.id, []);
|
||||
}
|
||||
|
||||
id2manager.set(data.id, managerItem);
|
||||
id2manager.get(data.id).push(managerItem);
|
||||
return managerItem;
|
||||
}
|
||||
}
|
||||
@ -130,9 +127,9 @@ export function registerDragEvent(manager, rootRender) {
|
||||
// 创建拖拽行为
|
||||
const drag = d3.drag();
|
||||
|
||||
drag.on('start', async event => dragStart(event, manager, rootRender));
|
||||
drag.on('drag', async event => dragged(event, manager, rootRender));
|
||||
drag.on('end', async event => dragEnd(event, manager, rootRender))
|
||||
drag.on('start', async event => await dragStart(event, manager, rootRender));
|
||||
drag.on('drag', async event => await dragged(event, manager, rootRender));
|
||||
drag.on('end', async event => await dragEnd(event, manager, rootRender))
|
||||
|
||||
manager.selection.call(drag);
|
||||
}
|
||||
@ -143,13 +140,105 @@ export function registerDragEvent(manager, rootRender) {
|
||||
* @param {BasicD3ManagmentItem} manager
|
||||
* @param {NetlistRender} rootRender
|
||||
*/
|
||||
function dragStart(event, manager, rootRender) {
|
||||
async function dragStart(event, manager, rootRender) {
|
||||
const selection = manager.selection;
|
||||
selection.attr('class', 'grabbing');
|
||||
|
||||
// 更新拓扑图中各个节点的节点坐标
|
||||
// 更新当前的 elkGraph
|
||||
const context = manager.dragContext;
|
||||
const nodes = [];
|
||||
const edges = [];
|
||||
|
||||
const layoutOptions = {
|
||||
// node 固定不动
|
||||
'org.eclipse.elk.stress.fixed': true,
|
||||
// node 的 port 固定不动
|
||||
'org.eclipse.elk.portConstraints': 'FIXED_POS'
|
||||
};
|
||||
|
||||
// 添加自己的节点
|
||||
const cell = manager.selection.datum();
|
||||
// 获取 connection
|
||||
|
||||
const id2manager = rootRender.id2manager;
|
||||
|
||||
const cellNode = {
|
||||
id: cell.id,
|
||||
x: cell.x,
|
||||
y: cell.y,
|
||||
width: cell.width,
|
||||
height: cell.height,
|
||||
// 后续遍历时获取该 port
|
||||
ports: [],
|
||||
layoutOptions
|
||||
};
|
||||
|
||||
// 添加邻居的节点和边
|
||||
for (const neighbor of context.neighbors) {
|
||||
const ndata = neighbor.selection.datum();
|
||||
const node = {
|
||||
id: ndata.id,
|
||||
width: ndata.width,
|
||||
height: ndata.height,
|
||||
x: ndata.x,
|
||||
y: ndata.y,
|
||||
ports: [],
|
||||
layoutOptions
|
||||
};
|
||||
|
||||
// 加入 port(如果有的话)
|
||||
for (const connection of neighbor.connections) {
|
||||
const conndata = connection.selection.datum();
|
||||
node.ports.push({
|
||||
id: conndata.id,
|
||||
width: conndata.width,
|
||||
height: conndata.height,
|
||||
x: conndata.x,
|
||||
y: conndata.y
|
||||
});
|
||||
}
|
||||
|
||||
nodes.push(node);
|
||||
|
||||
edges.push({
|
||||
id: neighbor.edge.id,
|
||||
source: neighbor.edge.source,
|
||||
sourcePort: neighbor.edge.sourcePort,
|
||||
target: neighbor.edge.target,
|
||||
targetPort: neighbor.edge.targetPort
|
||||
});
|
||||
|
||||
if (neighbor.location === 'source') {
|
||||
// 此时 cell 的 connection 就是 targetPort
|
||||
const cellConnectionId = neighbor.edge.targetPort;
|
||||
const connectionManager = id2manager.get(cellConnectionId)[0];
|
||||
const conndata = connectionManager.data;
|
||||
cellNode.ports.push({
|
||||
id: conndata.id,
|
||||
width: conndata.width,
|
||||
height: conndata.height,
|
||||
x: conndata.x,
|
||||
y: conndata.y
|
||||
});
|
||||
} else {
|
||||
// 此时 cell 的 connection 就是 sourcePort
|
||||
const cellConnectionId = neighbor.edge.sourcePort;
|
||||
const connectionManager = id2manager.get(cellConnectionId)[0];
|
||||
const conndata = connectionManager.data;
|
||||
cellNode.ports.push({
|
||||
id: conndata.id,
|
||||
width: conndata.width,
|
||||
height: conndata.height,
|
||||
x: conndata.x,
|
||||
y: conndata.y
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
nodes.push(cellNode);
|
||||
|
||||
context.elkGraph.children = nodes;
|
||||
context.elkGraph.edges = edges;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -158,7 +247,7 @@ function dragStart(event, manager, rootRender) {
|
||||
* @param {BasicD3ManagmentItem} manager
|
||||
* @param {NetlistRender} rootRender
|
||||
*/
|
||||
function dragged(event, manager, rootRender) {
|
||||
async function dragged(event, manager, rootRender) {
|
||||
// 当拖动结束时,D3 会根据绑定的数据(data.x 和 data.y)重新渲染元素,导致元素回到初始位置。
|
||||
// 所以需要 手动更新 data.x 和 data.y
|
||||
const selection = manager.selection;
|
||||
@ -173,7 +262,9 @@ function dragged(event, manager, rootRender) {
|
||||
|
||||
// 根据最小拓扑图,提取出关键点,重新计算布局
|
||||
const context = manager.dragContext;
|
||||
console.log(context.elkGraph);
|
||||
const elkGraph = context.elkGraph;
|
||||
const computedLayout = await rootRender.elk.layout(elkGraph);
|
||||
console.log(computedLayout);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -182,7 +273,7 @@ function dragged(event, manager, rootRender) {
|
||||
* @param {BasicD3ManagmentItem} manager
|
||||
* @param {NetlistRender} rootRender
|
||||
*/
|
||||
function dragEnd(event, manager, rootRender) {
|
||||
async function dragEnd(event, manager, rootRender) {
|
||||
const selection = manager.selection;
|
||||
selection.attr('class', 'grab');
|
||||
}
|
@ -92,7 +92,7 @@ export class ConnectionRender {
|
||||
id2manager.set(data.id, []);
|
||||
}
|
||||
|
||||
id2manager.set(data.id, managerItem);
|
||||
id2manager.get(data.id).push(managerItem);
|
||||
return managerItem;
|
||||
}
|
||||
}
|
||||
|
@ -121,25 +121,6 @@ export class NetlistRender {
|
||||
return layoutGraph;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 窗体大小发生变化时
|
||||
*/
|
||||
registerResizeHandler(element) {
|
||||
this.resizeMonitor = new ResizeObserver(entries => {
|
||||
for (const entry of entries) {
|
||||
const { height, width } = entry.contentRect;
|
||||
this.renderHeight = height;
|
||||
this.renderWidth = width;
|
||||
if (this.selection) {
|
||||
this.selection
|
||||
.attr('width', this.renderWidth)
|
||||
.attr('height', this.renderHeight)
|
||||
}
|
||||
}
|
||||
});
|
||||
this.resizeMonitor.observe(element);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {ElkNode} computedLayout
|
||||
@ -167,9 +148,13 @@ export class NetlistRender {
|
||||
// 将分组作为一个后续操作的 parent selection
|
||||
const g = svg.append('g');
|
||||
|
||||
// debug
|
||||
console.log(computedLayout);
|
||||
|
||||
// 生成连接
|
||||
await this.renderLine(g, computedLayout, ratio);
|
||||
|
||||
// 生成实体
|
||||
await this.renderEntity(g, computedLayout, ratio);
|
||||
|
||||
// svg 挂载为全局注册的 selection
|
||||
@ -181,6 +166,11 @@ export class NetlistRender {
|
||||
// 根据最大最小尺寸微调全局方位
|
||||
this.adjustLocation(g);
|
||||
|
||||
setTimeout(() => {
|
||||
// 生成各个 manager 的拖拽上下文
|
||||
this.createManagerDragContext(computedLayout);
|
||||
}, 1000);
|
||||
|
||||
return svg;
|
||||
}
|
||||
|
||||
@ -340,22 +330,77 @@ export class NetlistRender {
|
||||
this.zoom.transform,
|
||||
transform
|
||||
);
|
||||
}
|
||||
|
||||
// if (globalSetting.renderAnimation) {
|
||||
// parentSelection
|
||||
// .transition()
|
||||
// .duration(1000)
|
||||
// .attr('transform', transform);
|
||||
// } else {
|
||||
// parentSelection.attr('transform', transform);
|
||||
// }
|
||||
/**
|
||||
* @description 生成各个 manager 的拖拽上下文
|
||||
* @param {ElkNode} computedLayout
|
||||
*/
|
||||
createManagerDragContext(computedLayout) {
|
||||
const id2manager = this.id2manager;
|
||||
|
||||
/**
|
||||
* @returns {DragNeighbor}
|
||||
*/
|
||||
function makeDragNeighbor(id, portId) {
|
||||
if (id === portId) {
|
||||
// id 和 portId 都代表 port
|
||||
const manager = id2manager.get(id)[0];
|
||||
return {
|
||||
type: 'port',
|
||||
selection: manager.selection,
|
||||
connections: []
|
||||
}
|
||||
} else {
|
||||
// id 代表 cell, portId 代表 connection
|
||||
const cellManager = id2manager.get(id)[0];
|
||||
const connectionManager = id2manager.get(portId)[0];
|
||||
return {
|
||||
type: 'cell',
|
||||
selection: cellManager.selection,
|
||||
connections: [
|
||||
{ selection: connectionManager.selection }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const edge of computedLayout.edges) {
|
||||
// 遍历 edge,根据两侧 sourcePort 和 targetPort 将对应的 manager 中的 dragContext 进行更新
|
||||
const sourceNeighoor = makeDragNeighbor(edge.source, edge.sourcePort);
|
||||
const targetNeighoor = makeDragNeighbor(edge.target, edge.targetPort);
|
||||
|
||||
sourceNeighoor.location = 'source';
|
||||
targetNeighoor.location = 'target';
|
||||
sourceNeighoor.edge = edge;
|
||||
targetNeighoor.edge = edge;
|
||||
|
||||
const sourceManager = id2manager.get(edge.source)[0];
|
||||
const targetManager = id2manager.get(edge.target)[0];
|
||||
|
||||
sourceManager.dragContext.neighbors.push(targetNeighoor);
|
||||
targetManager.dragContext.neighbors.push(sourceNeighoor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @description 初次渲染完成后,布局不一定正确,需要进行调整(output ports)
|
||||
* @description 窗体大小发生变化时
|
||||
*/
|
||||
adjustLayoyt() {
|
||||
|
||||
registerResizeHandler(element) {
|
||||
this.resizeMonitor = new ResizeObserver(entries => {
|
||||
for (const entry of entries) {
|
||||
const { height, width } = entry.contentRect;
|
||||
this.renderHeight = height;
|
||||
this.renderWidth = width;
|
||||
if (this.selection) {
|
||||
this.selection
|
||||
.attr('width', this.renderWidth)
|
||||
.attr('height', this.renderHeight)
|
||||
}
|
||||
}
|
||||
});
|
||||
this.resizeMonitor.observe(element);
|
||||
}
|
||||
|
||||
}
|
@ -5,7 +5,6 @@
|
||||
import { globalLookup } from "../global";
|
||||
import { Cell, ModuleTree } from "./yosys";
|
||||
|
||||
export const SKIN_SCALE = 1;
|
||||
export const LINE_WIDTH = 2;
|
||||
|
||||
export const LAYOUT_CONSTANT = {
|
||||
@ -22,8 +21,8 @@ export const LAYOUT_CONSTANT = {
|
||||
CONSTANT_HEIGHT: 50,
|
||||
|
||||
// 器件的端口
|
||||
CELL_PORT_HEIGHT: 5,
|
||||
CELL_PORT_WIDTH: 5
|
||||
CELL_PORT_HEIGHT: 1,
|
||||
CELL_PORT_WIDTH: 1
|
||||
};
|
||||
|
||||
export const ELK_DIRECTION = {
|
||||
@ -121,8 +120,8 @@ export class Module {
|
||||
// 创建器件节点的 port, port 和 connection 一一对应
|
||||
const meta = skin.meta;
|
||||
|
||||
const height = meta.height * SKIN_SCALE;
|
||||
const width = meta.width * SKIN_SCALE;
|
||||
const height = meta.height;
|
||||
const width = meta.width;
|
||||
|
||||
const ports = [];
|
||||
|
||||
@ -141,14 +140,14 @@ export class Module {
|
||||
// 计算左侧的
|
||||
for (let i = 0; i < leftSideConnections.length; ++ i) {
|
||||
const connection = leftSideConnections[i];
|
||||
const yOffset = meta.getPortYOffset(connection.name) * SKIN_SCALE;
|
||||
const yOffset = meta.getPortYOffset(connection.name);
|
||||
|
||||
ports.push({
|
||||
id: connection.id,
|
||||
renderName: connection.name,
|
||||
renderType: 'cellPort',
|
||||
width: 1,
|
||||
height: 1,
|
||||
width: LAYOUT_CONSTANT.CELL_PORT_WIDTH,
|
||||
height: LAYOUT_CONSTANT.CELL_PORT_HEIGHT,
|
||||
x: 0,
|
||||
y: yOffset
|
||||
});
|
||||
@ -159,14 +158,14 @@ export class Module {
|
||||
// 计算右侧的
|
||||
for (let i = 0; i < rightSideConnections.length; ++ i) {
|
||||
const connection = rightSideConnections[i];
|
||||
const yOffset = meta.getPortYOffset(connection.name) * SKIN_SCALE;
|
||||
const yOffset = meta.getPortYOffset(connection.name);
|
||||
|
||||
ports.push({
|
||||
id: connection.id,
|
||||
renderName: connection.name,
|
||||
renderType: 'cellPort',
|
||||
width: 1,
|
||||
height: 1,
|
||||
width: LAYOUT_CONSTANT.CELL_PORT_WIDTH,
|
||||
height: LAYOUT_CONSTANT.CELL_PORT_HEIGHT,
|
||||
x: width,
|
||||
y: yOffset
|
||||
});
|
||||
@ -267,8 +266,10 @@ export class Module {
|
||||
// 创建常数到器件的连线
|
||||
const edge = {
|
||||
id: makeEdgeId(cell.id, id),
|
||||
sources: [connection.id],
|
||||
targets: [id]
|
||||
source: cell.id,
|
||||
sourcePort: connection.id,
|
||||
target: id,
|
||||
targetPort: id
|
||||
};
|
||||
|
||||
edges.push(edge);
|
||||
|
@ -111,6 +111,7 @@ export class PortRender {
|
||||
const id2manager = this.id2manager;
|
||||
// 创建拖拽上下文
|
||||
const dragContext = {
|
||||
neighbors: [],
|
||||
elkGraph: {
|
||||
// elk 是无状态的,id 取什么名字都行
|
||||
id: 'root',
|
||||
@ -130,7 +131,7 @@ export class PortRender {
|
||||
id2manager.set(data.id, []);
|
||||
}
|
||||
|
||||
id2manager.set(data.id, managerItem);
|
||||
id2manager.get(data.id).push(managerItem);
|
||||
return managerItem;
|
||||
}
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ export class WireRender {
|
||||
id2manager.set(data.id, []);
|
||||
}
|
||||
|
||||
id2manager.set(data.id, managerItem);
|
||||
id2manager.get(data.id).push(managerItem);
|
||||
return managerItem;
|
||||
}
|
||||
}
|
@ -74,8 +74,8 @@ class SkinMeta {
|
||||
|
||||
const svgDoc = parser.parseFromString(svgString, 'image/svg+xml');
|
||||
const element = svgDoc.documentElement;
|
||||
this.width = element.getAttribute('width');
|
||||
this.height = element.getAttribute('height');
|
||||
this.width = parseFloat(element.getAttribute('width'));
|
||||
this.height = parseFloat(element.getAttribute('height'));
|
||||
this.svgDoc = svgDoc;
|
||||
|
||||
/**
|
||||
|
@ -9,5 +9,10 @@
|
||||
"tips": "نصائح",
|
||||
"language-setting": "اللغة",
|
||||
"setting.language.change-dialog": "لقد قمت بتغيير اللغة إلى {0} ، ونوصي بإعادة تشغيل Netlist Viewer",
|
||||
"render-animation": "تفعيل الرسوم المتحركة للعرض"
|
||||
"render-animation": "تفعيل الرسوم المتحركة للعرض",
|
||||
"usermanual": "دليل المستخدم",
|
||||
"usermanual.click-move": "انقر + اسحب",
|
||||
"usermanual.move-view": "عرض الجوال",
|
||||
"usermanual.scale-view": "تكبير/تصغير العرض",
|
||||
"usermanual.scale-view-more": "تكبير العرض (مقياس أكبر)"
|
||||
}
|
@ -9,5 +9,10 @@
|
||||
"tips": "Tipps",
|
||||
"language-setting": "Sprache",
|
||||
"setting.language.change-dialog": "Sie haben die Sprache auf {0} geändert. Wir empfehlen Ihnen, Netlist Viewer neu zu starten.",
|
||||
"render-animation": "Rendering-Animation aktivieren"
|
||||
"render-animation": "Rendering-Animation aktivieren",
|
||||
"usermanual": "Benutzerhandbuch",
|
||||
"usermanual.click-move": "Klicken + Ziehen",
|
||||
"usermanual.move-view": "Mobile Ansicht",
|
||||
"usermanual.scale-view": "Ansicht zoomen",
|
||||
"usermanual.scale-view-more": "Ansicht vergrößern (größerer Maßstab)"
|
||||
}
|
File diff suppressed because one or more lines are too long
@ -9,5 +9,10 @@
|
||||
"tips": "Conseils",
|
||||
"language-setting": "Langue",
|
||||
"setting.language.change-dialog": "Vous avez changé la langue en {0}, nous vous recommandons de redémarrer Netlist Viewer.",
|
||||
"render-animation": "Activer l'animation de rendu"
|
||||
"render-animation": "Activer l'animation de rendu",
|
||||
"usermanual": "Manuel utilisateur",
|
||||
"usermanual.click-move": "Cliquer + Glisser",
|
||||
"usermanual.move-view": "Vue mobile",
|
||||
"usermanual.scale-view": "Zoom de la vue",
|
||||
"usermanual.scale-view-more": "Zoom de la vue (échelle plus grande)"
|
||||
}
|
@ -9,5 +9,10 @@
|
||||
"tips": "ヒント",
|
||||
"language-setting": "言語",
|
||||
"setting.language.change-dialog": "言語を {0} に変更しました。Netlist Viewer を再起動することをお勧めします。",
|
||||
"render-animation": "レンダリングアニメーションを有効にする"
|
||||
"render-animation": "レンダリングアニメーションを有効にする",
|
||||
"usermanual": "使用説明",
|
||||
"usermanual.click-move": "クリック + ドラッグ",
|
||||
"usermanual.move-view": "モバイル表示",
|
||||
"usermanual.scale-view": "ビューのズーム",
|
||||
"usermanual.scale-view-more": "ビューのズーム(より大きなスケール)"
|
||||
}
|
@ -9,5 +9,10 @@
|
||||
"tips": "팁",
|
||||
"language-setting": "언어",
|
||||
"setting.language.change-dialog": "언어를 {0} 으로 변경했습니다. Netlist Viewer 를 다시 시작하는 것을 권장합니다.",
|
||||
"render-animation": "렌더링 애니메이션 활성화"
|
||||
"render-animation": "렌더링 애니메이션 활성화",
|
||||
"usermanual": "사용 설명서",
|
||||
"usermanual.click-move": "클릭 + 드래그",
|
||||
"usermanual.move-view": "모바일 보기",
|
||||
"usermanual.scale-view": "보기 확대/축소",
|
||||
"usermanual.scale-view-more": "보기 확대 (더 큰 스케일)"
|
||||
}
|
@ -9,5 +9,10 @@
|
||||
"tips": "Советы",
|
||||
"language-setting": "Язык",
|
||||
"setting.language.change-dialog": "Вы изменили язык на {0}, мы рекомендуем перезапустить Netlist Viewer.",
|
||||
"render-animation": "Включить анимацию рендеринга"
|
||||
"render-animation": "Включить анимацию рендеринга",
|
||||
"usermanual": "Руководство пользователя",
|
||||
"usermanual.click-move": "Клик + Перетаскивание",
|
||||
"usermanual.move-view": "Мобильный вид",
|
||||
"usermanual.scale-view": "Масштабирование вида",
|
||||
"usermanual.scale-view-more": "Масштабирование вида (больший масштаб)"
|
||||
}
|
@ -9,5 +9,10 @@
|
||||
"tips": "提示",
|
||||
"language-setting": "语言",
|
||||
"setting.language.change-dialog": "您已经更换语言为 {0} ,我们建议您重启 Netlist Viewer",
|
||||
"render-animation": "开启渲染动画"
|
||||
"render-animation": "开启渲染动画",
|
||||
"usermanual": "使用说明",
|
||||
"usermanual.click-move": "点击 + 拖动",
|
||||
"usermanual.move-view": "移动视图",
|
||||
"usermanual.scale-view": "视图缩放",
|
||||
"usermanual.scale-view-more": "视图缩放(尺度更大)"
|
||||
}
|
@ -9,5 +9,10 @@
|
||||
"tips": "提示",
|
||||
"language-setting": "語言",
|
||||
"setting.language.change-dialog": "您已將語言更改為 {0} ,我們建議您重新啟動 Netlist Viewer。",
|
||||
"render-animation": "開啟渲染動畫"
|
||||
"render-animation": "開啟渲染動畫",
|
||||
"usermanual": "使用說明",
|
||||
"usermanual.click-move": "點擊 + 拖動",
|
||||
"usermanual.move-view": "移動視圖",
|
||||
"usermanual.scale-view": "視圖縮放",
|
||||
"usermanual.scale-view-more": "視圖縮放(尺度更大)"
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user