From c4c6605174b89e5c8ed682d090b2ec8c443f91f9 Mon Sep 17 00:00:00 2001 From: Kirigaya <1193466151@qq.com> Date: Thu, 2 Jan 2025 03:38:46 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20netlist=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/index.html | 4 +- public/netlist.json | 630 ++++++++++++++++++++++++++++++++++++++ public/netlist.v | 35 +++ src/hook/render/layout.js | 38 ++- src/hook/render/wire.js | 70 ++++- src/hook/skin/draw.js | 8 + src/hook/skin/index.js | 25 ++ 7 files changed, 793 insertions(+), 17 deletions(-) create mode 100644 public/netlist.json create mode 100644 public/netlist.v diff --git a/public/index.html b/public/index.html index b8b5b9f..8760ed8 100644 --- a/public/index.html +++ b/public/index.html @@ -15,7 +15,7 @@ diff --git a/public/netlist.json b/public/netlist.json new file mode 100644 index 0000000..fc211a3 --- /dev/null +++ b/public/netlist.json @@ -0,0 +1,630 @@ +{ + "creator": "Yosys 0.48+5 (git sha1 7a362f1f7, clang++ 18.1.2-wasi-sdk -Oz)", + "modules": { + "netlistview": { + "attributes": { + "cells_not_processed": "00000000000000000000000000000001", + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:2.1-36.10" + }, + "ports": { + "clock": { + "direction": "input", + "bits": [ 2 ] + }, + "data_in": { + "direction": "input", + "bits": [ 3, 4, 5, 6, 7, 8, 9, 10, 11 ] + }, + "up": { + "direction": "input", + "bits": [ 12 ] + }, + "down": { + "direction": "input", + "bits": [ 13 ] + }, + "carry_out": { + "direction": "output", + "bits": [ 14 ] + }, + "borrow_out": { + "direction": "output", + "bits": [ 15 ] + }, + "count_out": { + "direction": "output", + "bits": [ 16, 17, 18, 19, 20, 21, 22, 23, 24 ] + }, + "parity_out": { + "direction": "output", + "bits": [ 25 ] + } + }, + "cells": { + "$add$/dide/user/src/language/vlog/netlistview/netlistview.v:15$3": { + "hide_name": 1, + "type": "$add", + "parameters": { + "A_SIGNED": "00000000000000000000000000000000", + "A_WIDTH": "00000000000000000000000000001001", + "B_SIGNED": "00000000000000000000000000000000", + "B_WIDTH": "00000000000000000000000000000010", + "Y_WIDTH": "00000000000000000000000000001010" + }, + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:15.18-15.36" + }, + "port_directions": { + "A": "input", + "B": "input", + "Y": "output" + }, + "connections": { + "A": [ 16, 17, 18, 19, 20, 21, 22, 23, 24 ], + "B": [ "1", "1" ], + "Y": [ 26, 27, 28, 29, 30, 31, 32, 33, 34, 35 ] + } + }, + "$and$/dide/user/src/language/vlog/netlistview/netlistview.v:31$5": { + "hide_name": 1, + "type": "$and", + "parameters": { + "A_SIGNED": "00000000000000000000000000000000", + "A_WIDTH": "00000000000000000000000000000001", + "B_SIGNED": "00000000000000000000000000000000", + "B_WIDTH": "00000000000000000000000000000001", + "Y_WIDTH": "00000000000000000000000000000001" + }, + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:31.24-31.38" + }, + "port_directions": { + "A": "input", + "B": "input", + "Y": "output" + }, + "connections": { + "A": [ 12 ], + "B": [ 35 ], + "Y": [ 36 ] + } + }, + "$and$/dide/user/src/language/vlog/netlistview/netlistview.v:32$6": { + "hide_name": 1, + "type": "$and", + "parameters": { + "A_SIGNED": "00000000000000000000000000000000", + "A_WIDTH": "00000000000000000000000000000001", + "B_SIGNED": "00000000000000000000000000000000", + "B_WIDTH": "00000000000000000000000000000001", + "Y_WIDTH": "00000000000000000000000000000001" + }, + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:32.24-32.40" + }, + "port_directions": { + "A": "input", + "B": "input", + "Y": "output" + }, + "connections": { + "A": [ 13 ], + "B": [ 37 ], + "Y": [ 38 ] + } + }, + "$procdff$12": { + "hide_name": 1, + "type": "$dff", + "parameters": { + "CLK_POLARITY": "1", + "WIDTH": "00000000000000000000000000001001" + }, + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:13.5-34.8" + }, + "port_directions": { + "CLK": "input", + "D": "input", + "Q": "output" + }, + "connections": { + "CLK": [ 2 ], + "D": [ 39, 40, 41, 42, 43, 44, 45, 46, 47 ], + "Q": [ 16, 17, 18, 19, 20, 21, 22, 23, 24 ] + } + }, + "$procdff$13": { + "hide_name": 1, + "type": "$dff", + "parameters": { + "CLK_POLARITY": "1", + "WIDTH": "00000000000000000000000000000001" + }, + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:13.5-34.8" + }, + "port_directions": { + "CLK": "input", + "D": "input", + "Q": "output" + }, + "connections": { + "CLK": [ 2 ], + "D": [ 36 ], + "Q": [ 14 ] + } + }, + "$procdff$14": { + "hide_name": 1, + "type": "$dff", + "parameters": { + "CLK_POLARITY": "1", + "WIDTH": "00000000000000000000000000000001" + }, + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:13.5-34.8" + }, + "port_directions": { + "CLK": "input", + "D": "input", + "Q": "output" + }, + "connections": { + "CLK": [ 2 ], + "D": [ 38 ], + "Q": [ 15 ] + } + }, + "$procdff$15": { + "hide_name": 1, + "type": "$dff", + "parameters": { + "CLK_POLARITY": "1", + "WIDTH": "00000000000000000000000000000001" + }, + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:13.5-34.8" + }, + "port_directions": { + "CLK": "input", + "D": "input", + "Q": "output" + }, + "connections": { + "CLK": [ 2 ], + "D": [ 48 ], + "Q": [ 25 ] + } + }, + "$procdff$16": { + "hide_name": 1, + "type": "$dff", + "parameters": { + "CLK_POLARITY": "1", + "WIDTH": "00000000000000000000000000001010" + }, + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:13.5-34.8" + }, + "port_directions": { + "CLK": "input", + "D": "input", + "Q": "output" + }, + "connections": { + "CLK": [ 2 ], + "D": [ 26, 27, 28, 29, 30, 31, 32, 33, 34, 35 ], + "Q": [ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58 ] + } + }, + "$procdff$17": { + "hide_name": 1, + "type": "$dff", + "parameters": { + "CLK_POLARITY": "1", + "WIDTH": "00000000000000000000000000001010" + }, + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:13.5-34.8" + }, + "port_directions": { + "CLK": "input", + "D": "input", + "Q": "output" + }, + "connections": { + "CLK": [ 2 ], + "D": [ 59, 60, 61, 62, 63, 64, 65, 66, 67, 37 ], + "Q": [ 68, 69, 70, 71, 72, 73, 74, 75, 76, 77 ] + } + }, + "$procdff$18": { + "hide_name": 1, + "type": "$dff", + "parameters": { + "CLK_POLARITY": "1", + "WIDTH": "00000000000000000000000000001001" + }, + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:13.5-34.8" + }, + "port_directions": { + "CLK": "input", + "D": "input", + "Q": "output" + }, + "connections": { + "CLK": [ 2 ], + "D": [ 39, 40, 41, 42, 43, 44, 45, 46, 47 ], + "Q": [ 78, 79, 80, 81, 82, 83, 84, 85, 86 ] + } + }, + "$procmux$10_CMP0": { + "hide_name": 1, + "type": "$eq", + "parameters": { + "A_SIGNED": "00000000000000000000000000000000", + "A_WIDTH": "00000000000000000000000000000010", + "B_SIGNED": "00000000000000000000000000000000", + "B_WIDTH": "00000000000000000000000000000010", + "Y_WIDTH": "00000000000000000000000000000001" + }, + "attributes": { + "full_case": "00000000000000000000000000000001", + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:0.0-0.0|/dide/user/src/language/vlog/netlistview/netlistview.v:17.9-28.16" + }, + "port_directions": { + "A": "input", + "B": "input", + "Y": "output" + }, + "connections": { + "A": [ 13, 12 ], + "B": [ "1", "0" ], + "Y": [ 87 ] + } + }, + "$procmux$11_CMP0": { + "hide_name": 1, + "type": "$logic_not", + "parameters": { + "A_SIGNED": "00000000000000000000000000000000", + "A_WIDTH": "00000000000000000000000000000010", + "Y_WIDTH": "00000000000000000000000000000001" + }, + "attributes": { + "full_case": "00000000000000000000000000000001", + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:0.0-0.0|/dide/user/src/language/vlog/netlistview/netlistview.v:17.9-28.16" + }, + "port_directions": { + "A": "input", + "Y": "output" + }, + "connections": { + "A": [ 13, 12 ], + "Y": [ 88 ] + } + }, + "$procmux$7": { + "hide_name": 1, + "type": "$pmux", + "parameters": { + "S_WIDTH": "00000000000000000000000000000100", + "WIDTH": "00000000000000000000000000001001" + }, + "attributes": { + "full_case": "00000000000000000000000000000001", + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:0.0-0.0|/dide/user/src/language/vlog/netlistview/netlistview.v:17.9-28.16" + }, + "port_directions": { + "A": "input", + "B": "input", + "S": "input", + "Y": "output" + }, + "connections": { + "A": [ "x", "x", "x", "x", "x", "x", "x", "x", "x" ], + "B": [ 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 27, 28, 29, 30, 31, 32, 33, 34, 59, 60, 61, 62, 63, 64, 65, 66, 67, 3, 4, 5, 6, 7, 8, 9, 10, 11 ], + "S": [ 89, 90, 87, 88 ], + "Y": [ 39, 40, 41, 42, 43, 44, 45, 46, 47 ] + } + }, + "$procmux$8_CMP0": { + "hide_name": 1, + "type": "$eq", + "parameters": { + "A_SIGNED": "00000000000000000000000000000000", + "A_WIDTH": "00000000000000000000000000000010", + "B_SIGNED": "00000000000000000000000000000000", + "B_WIDTH": "00000000000000000000000000000010", + "Y_WIDTH": "00000000000000000000000000000001" + }, + "attributes": { + "full_case": "00000000000000000000000000000001", + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:0.0-0.0|/dide/user/src/language/vlog/netlistview/netlistview.v:17.9-28.16" + }, + "port_directions": { + "A": "input", + "B": "input", + "Y": "output" + }, + "connections": { + "A": [ 13, 12 ], + "B": [ "1", "1" ], + "Y": [ 89 ] + } + }, + "$procmux$9_CMP0": { + "hide_name": 1, + "type": "$eq", + "parameters": { + "A_SIGNED": "00000000000000000000000000000000", + "A_WIDTH": "00000000000000000000000000000010", + "B_SIGNED": "00000000000000000000000000000000", + "B_WIDTH": "00000000000000000000000000000010", + "Y_WIDTH": "00000000000000000000000000000001" + }, + "attributes": { + "full_case": "00000000000000000000000000000001", + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:0.0-0.0|/dide/user/src/language/vlog/netlistview/netlistview.v:17.9-28.16" + }, + "port_directions": { + "A": "input", + "B": "input", + "Y": "output" + }, + "connections": { + "A": [ 13, 12 ], + "B": [ "0", "1" ], + "Y": [ 90 ] + } + }, + "$reduce_xor$/dide/user/src/language/vlog/netlistview/netlistview.v:30$4": { + "hide_name": 1, + "type": "$reduce_xor", + "parameters": { + "A_SIGNED": "00000000000000000000000000000000", + "A_WIDTH": "00000000000000000000000000001001", + "Y_WIDTH": "00000000000000000000000000000001" + }, + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:30.24-30.34" + }, + "port_directions": { + "A": "input", + "Y": "output" + }, + "connections": { + "A": [ 39, 40, 41, 42, 43, 44, 45, 46, 47 ], + "Y": [ 48 ] + } + }, + "$sub$/dide/user/src/language/vlog/netlistview/netlistview.v:14$2": { + "hide_name": 1, + "type": "$sub", + "parameters": { + "A_SIGNED": "00000000000000000000000000000000", + "A_WIDTH": "00000000000000000000000000001001", + "B_SIGNED": "00000000000000000000000000000000", + "B_WIDTH": "00000000000000000000000000000011", + "Y_WIDTH": "00000000000000000000000000001010" + }, + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:14.18-14.37" + }, + "port_directions": { + "A": "input", + "B": "input", + "Y": "output" + }, + "connections": { + "A": [ 16, 17, 18, 19, 20, 21, 22, 23, 24 ], + "B": [ "1", "0", "1" ], + "Y": [ 59, 60, 61, 62, 63, 64, 65, 66, 67, 37 ] + } + } + }, + "netnames": { + "$0\\borrow_out[0:0]": { + "hide_name": 1, + "bits": [ 38 ], + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:13.5-34.8" + } + }, + "$0\\carry_out[0:0]": { + "hide_name": 1, + "bits": [ 36 ], + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:13.5-34.8" + } + }, + "$0\\cnt_dn[9:0]": { + "hide_name": 1, + "bits": [ 59, 60, 61, 62, 63, 64, 65, 66, 67, 37 ], + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:13.5-34.8" + } + }, + "$0\\cnt_up[9:0]": { + "hide_name": 1, + "bits": [ 26, 27, 28, 29, 30, 31, 32, 33, 34, 35 ], + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:13.5-34.8" + } + }, + "$0\\count_nxt[8:0]": { + "hide_name": 1, + "bits": [ 39, 40, 41, 42, 43, 44, 45, 46, 47 ], + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:13.5-34.8" + } + }, + "$0\\count_out[8:0]": { + "hide_name": 1, + "bits": [ 39, 40, 41, 42, 43, 44, 45, 46, 47 ], + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:13.5-34.8" + } + }, + "$0\\parity_out[0:0]": { + "hide_name": 1, + "bits": [ 48 ], + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:13.5-34.8" + } + }, + "$1\\count_nxt[8:0]": { + "hide_name": 1, + "bits": [ 39, 40, 41, 42, 43, 44, 45, 46, 47 ], + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:13.5-34.8" + } + }, + "$add$/dide/user/src/language/vlog/netlistview/netlistview.v:15$3_Y": { + "hide_name": 1, + "bits": [ 26, 27, 28, 29, 30, 31, 32, 33, 34, 35 ], + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:15.18-15.36" + } + }, + "$and$/dide/user/src/language/vlog/netlistview/netlistview.v:31$5_Y": { + "hide_name": 1, + "bits": [ 36 ], + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:31.24-31.38" + } + }, + "$and$/dide/user/src/language/vlog/netlistview/netlistview.v:32$6_Y": { + "hide_name": 1, + "bits": [ 38 ], + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:32.24-32.40" + } + }, + "$procmux$10_CMP": { + "hide_name": 1, + "bits": [ 87 ], + "attributes": { + } + }, + "$procmux$11_CMP": { + "hide_name": 1, + "bits": [ 88 ], + "attributes": { + } + }, + "$procmux$7_Y": { + "hide_name": 1, + "bits": [ 39, 40, 41, 42, 43, 44, 45, 46, 47 ], + "attributes": { + } + }, + "$procmux$8_CMP": { + "hide_name": 1, + "bits": [ 89 ], + "attributes": { + } + }, + "$procmux$9_CMP": { + "hide_name": 1, + "bits": [ 90 ], + "attributes": { + } + }, + "$reduce_xor$/dide/user/src/language/vlog/netlistview/netlistview.v:30$4_Y": { + "hide_name": 1, + "bits": [ 48 ], + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:30.24-30.34" + } + }, + "$sub$/dide/user/src/language/vlog/netlistview/netlistview.v:14$2_Y": { + "hide_name": 1, + "bits": [ 59, 60, 61, 62, 63, 64, 65, 66, 67, 37 ], + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:14.18-14.37" + } + }, + "borrow_out": { + "hide_name": 0, + "bits": [ 15 ], + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:8.27-8.37" + } + }, + "carry_out": { + "hide_name": 0, + "bits": [ 14 ], + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:8.16-8.25" + } + }, + "clock": { + "hide_name": 0, + "bits": [ 2 ], + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:5.11-5.16" + } + }, + "cnt_dn": { + "hide_name": 0, + "bits": [ 68, 69, 70, 71, 72, 73, 74, 75, 76, 77 ], + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:10.23-10.29" + } + }, + "cnt_up": { + "hide_name": 0, + "bits": [ 49, 50, 51, 52, 53, 54, 55, 56, 57, 58 ], + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:10.15-10.21" + } + }, + "count_nxt": { + "hide_name": 0, + "bits": [ 78, 79, 80, 81, 82, 83, 84, 85, 86 ], + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:11.15-11.24" + } + }, + "count_out": { + "hide_name": 0, + "bits": [ 16, 17, 18, 19, 20, 21, 22, 23, 24 ], + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:7.22-7.31" + } + }, + "data_in": { + "hide_name": 0, + "bits": [ 3, 4, 5, 6, 7, 8, 9, 10, 11 ], + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:4.17-4.24" + } + }, + "down": { + "hide_name": 0, + "bits": [ 13 ], + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:5.22-5.26" + } + }, + "parity_out": { + "hide_name": 0, + "bits": [ 25 ], + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:8.39-8.49" + } + }, + "up": { + "hide_name": 0, + "bits": [ 12 ], + "attributes": { + "src": "/dide/user/src/language/vlog/netlistview/netlistview.v:5.18-5.20" + } + } + } + } + } + } \ No newline at end of file diff --git a/public/netlist.v b/public/netlist.v new file mode 100644 index 0000000..8424a15 --- /dev/null +++ b/public/netlist.v @@ -0,0 +1,35 @@ +module netlistview(clock, data_in, up, down, carry_out, borrow_out, count_out, parity_out); + + input [8:0] data_in; + input clock, up, down; + + output reg [8:0] count_out; + output reg carry_out, borrow_out, parity_out; + + reg [9:0] cnt_up, cnt_dn; + reg [8:0] count_nxt; + + always @(posedge clock) begin + cnt_dn = count_out - 3'b 101; + cnt_up = count_out + 2'b 11; + + case ({up,down}) + 2'b 00 : + count_nxt = data_in; + 2'b 01 : + count_nxt = cnt_dn; + 2'b 10 : + count_nxt = cnt_up; + 2'b 11 : + count_nxt = count_out; + default : + count_nxt = 9'bX; + endcase + + parity_out <= ^count_nxt; + carry_out <= up & cnt_up[9]; + borrow_out <= down & cnt_dn[9]; + count_out <= count_nxt; + end + +endmodule \ No newline at end of file diff --git a/src/hook/render/layout.js b/src/hook/render/layout.js index a1f3288..5d1e814 100644 --- a/src/hook/render/layout.js +++ b/src/hook/render/layout.js @@ -277,7 +277,10 @@ export class Module { // 当前的器件的这个端口和某一个 port 连接 const port = tree.wireIdToPort.get(wireId); - if (port.direction === 'input') { + // 器件的端口的方向有比 port 更高的优先级。 + // 器件当前的口为 input,那么所连接的 port 就必须是 input,即便这个 port 是 output + + if (connection.direction === 'input') { const edge = { // id 遵循 sourcePort-targetPort id: makeEdgeId(port.id, connection.id), @@ -357,15 +360,40 @@ export class Module { // 统计分配到左右两侧的 port const leftSideConnections = []; const rightSideConnections = []; + const topSideConnections = []; - for (const conn of cell.nameToConnection.values()) { - if (conn.direction === 'input') { - leftSideConnections.push(conn); + for (const connection of cell.nameToConnection.values()) { + const yOffset = meta.getPortYOffset(connection.name); + if (yOffset === 0) { + topSideConnections.push(connection); + } else if (connection.direction === 'input') { + leftSideConnections.push(connection); } else { - rightSideConnections.push(conn); + rightSideConnections.push(connection); } } + // 计算上侧的 + for (let i = 0; i < topSideConnections.length; ++ i) { + const connection = topSideConnections[i]; + const xOffset = meta.getPortXOffset(connection.name); + + console.log(xOffset); + + ports.push({ + id: connection.id, + renderName: connection.name, + renderType: 'cellPort', + direction: 'input', + source: 'cell', + isVertical: true, + width: LAYOUT_CONSTANT.CELL_PORT_WIDTH, + height: LAYOUT_CONSTANT.CELL_PORT_HEIGHT, + x: xOffset, + y: 0 + }); + } + // 计算左侧的 for (let i = 0; i < leftSideConnections.length; ++ i) { const connection = leftSideConnections[i]; diff --git a/src/hook/render/wire.js b/src/hook/render/wire.js index 7220b44..9412f3c 100644 --- a/src/hook/render/wire.js +++ b/src/hook/render/wire.js @@ -45,6 +45,7 @@ export class WireRender { const beginPoint = points.at(0); const endPoint = points.at(-1); + const lastTwoPoint = points.at(-2); const sourcePort = id2port.get(edge.sourcePort); const targetPort = id2port.get(edge.targetPort); @@ -52,14 +53,21 @@ export class WireRender { const targetMargin = getMarginParamter(targetPort); beginPoint.x -= sourceMargin.rightMargin; + const direction = judgeDirection(endPoint, lastTwoPoint); // 特殊情况: targetPort 为 undefined if (targetPort === undefined) { - const port = id2port.get(edge.orginalTarget); + const port = id2port.get(edge.orginalTarget); // TODO: 检查正确性 endPoint.x -= LAYOUT_CONSTANT.INSTANCE_RIGHT_MARGIN; } else { - endPoint.x += targetMargin.leftMargin; + // 判断当前的方向 + if (direction === 'up' || direction === 'down') { + lastTwoPoint.x += targetMargin.leftMargin + 1; + endPoint.x += targetMargin.leftMargin + 1; + } else { + endPoint.x += targetMargin.leftMargin; + } } for (let i = 0; i < points.length; ++ i) { @@ -72,21 +80,16 @@ export class WireRender { const lineSvg = linePaths.join(' '); - // 判断当前的朝向 - const direction = endPoint.x > points.at(-2).x ? 'right' : 'left'; - const arrowX = direction === 'right' ? endPoint.x - LAYOUT_CONSTANT.CELL_PORT_WIDTH - this.arrowWidth + 2.5: - endPoint.x + LAYOUT_CONSTANT.CELL_PORT_WIDTH - 2.5 + const arrowLocation = getArrowLocation(endPoint, direction, this.arrowWidth, this.arrowHeight); - const arrowY = endPoint.y - this.arrowHeight / 2; - this.data.push({ id: this.idCounter, svg: lineSvg, endPoint: points.at(-1), arrow: { icon: direction + '-arrow', - x: arrowX, - y: arrowY, + x: arrowLocation.x, + y: arrowLocation.y, width: this.arrowWidth, height: this.arrowHeight }, @@ -239,4 +242,51 @@ export class WireRender { function cubicBezierAnimation(delta, oldVal, newVal) { delta = 3 * (1 - delta) * (1 - delta) * delta + 3 * (1 - delta) * delta * delta + delta * delta * delta; return (1 - delta) * oldVal + delta * newVal; +} + + +/** + * + * @param {import('../jsdoc').ElkPoint} lastPoint + * @param {import('../jsdoc').ElkPoint} lastTowPoint + * @returns {'left' | 'right' | 'up' | 'down'} + */ +function judgeDirection(lastPoint, lastTowPoint) { + if (lastPoint.x !== lastTowPoint.x) { + return lastPoint.x > lastTowPoint.x ? 'right': 'left'; + } else { + return lastPoint.y > lastTowPoint.y ? 'down': 'up'; + } +} + +/** + * + * @param {import('../jsdoc').ElkPoint} lastPoint + * @param {'left' | 'right' | 'up' | 'down'} direction + */ +function getArrowLocation(lastPoint, direction, arrowWidth, arrowHeight) { + switch (direction) { + case 'left': + return { + x: lastPoint.x + LAYOUT_CONSTANT.CELL_PORT_WIDTH - 2.5, + y: lastPoint.y - arrowHeight / 2 + }; + case 'right': + return { + x: lastPoint.x - LAYOUT_CONSTANT.CELL_PORT_WIDTH - arrowWidth + 2.5, + y: lastPoint.y - arrowHeight / 2 + }; + case 'up': + return { + x: lastPoint.x + LAYOUT_CONSTANT.CELL_PORT_WIDTH - arrowWidth / 2 - 1, + y: lastPoint.y - arrowHeight / 2 + }; + case 'down': + return { + x: lastPoint.x + LAYOUT_CONSTANT.CELL_PORT_WIDTH - arrowWidth / 2 - 1, + y: lastPoint.y - arrowHeight / 2 - 5 + }; + default: + break; + } } \ No newline at end of file diff --git a/src/hook/skin/draw.js b/src/hook/skin/draw.js index 1b59e86..4bfae4a 100644 --- a/src/hook/skin/draw.js +++ b/src/hook/skin/draw.js @@ -12,6 +12,14 @@ export const DIDE_DRAW_SVG_STRINGS = [ { name: 'left-arrow', source: '' + }, + { + name: 'down-arrow', + source: '' + }, + { + name: 'up-arrow', + source: '' } ]; diff --git a/src/hook/skin/index.js b/src/hook/skin/index.js index 7eb2dc9..263f9cd 100644 --- a/src/hook/skin/index.js +++ b/src/hook/skin/index.js @@ -103,6 +103,11 @@ class SkinMeta { this.height = parseFloat(element.getAttribute('height')); this.svgDoc = svgDoc; + /** + * @type {Map} + */ + this.portToXOffset = new Map(); + /** * @type {Map} */ @@ -127,4 +132,24 @@ class SkinMeta { this.portToYOffset.set(portName, yOffset); return yOffset; } + + /** + * @description 获取指定 port 在所在 svg 中 Y 轴的相对偏移量 + * @param {string} portName + */ + getPortXOffset(portName) { + if (this.portToXOffset.has(portName)) { + return this.portToXOffset.get(portName); + } + // 没有 hit,尝试获取 + const pathElement = this.svgDoc.getElementById(portName); + if (pathElement === null) { + return 0; + } + const transform = pathElement.getAttribute('transform'); + const offsetnumber = transform.split('(').at(-1).split(' ').at(0); + const xOffset = parseFloat(offsetnumber); + this.portToXOffset.set(portName, xOffset); + return xOffset; + } } \ No newline at end of file