@tscircuit/schematic-viewer 1.2.14 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/chromatic.yml +30 -0
- package/.github/workflows/npm-build.yml +26 -0
- package/.github/workflows/npm-typecheck.yml +26 -0
- package/README.md +1 -1
- package/dist/index.d.ts +6 -7
- package/dist/index.js +690 -664
- package/dist/index.js.map +1 -1
- package/package.json +21 -12
- package/renovate.json +12 -1
- package/src/Schematic.tsx +148 -77
- package/src/lib/types/core.ts +14 -49
- package/src/lib/types/source-component.ts +6 -0
- package/src/lib/utils/collect-element-refs.ts +4 -3
- package/src/lib/utils/colors.ts +236 -0
- package/src/schematic-components/SVGPathComponent.tsx +84 -144
- package/src/schematic-components/SchematicChip.tsx +183 -0
- package/src/schematic-components/SchematicComponent.tsx +18 -24
- package/src/schematic-components/SchematicComponentFromSymbol.tsx +44 -0
- package/src/schematic-components/SchematicElement.tsx +4 -38
- package/src/schematic-components/SchematicTrace.tsx +4 -3
- package/src/schematic-components/index.tsx +7 -14
- package/src/stories/basics/schematic-net-label.stories.tsx +112 -166
- package/src/stories/basics/schematic-net-labels-2.stories.tsx +22 -20
- package/src/stories/bug-connections.stories.tsx +9 -6
- package/src/stories/bug-high-port-numbers.stories.tsx +99 -82
- package/src/stories/bug-pin-spacing.stories.tsx +1 -0
- package/src/stories/bugs/bug1-y-flip.stories.tsx +3 -2
- package/src/stories/bugs/bug3-scaling-trace.stories.tsx +11 -5
- package/src/stories/bugs/bug4-schematic-line.stories.tsx +0 -1
- package/src/stories/bugs/bug5-diode.stories.tsx +0 -1
- package/src/stories/bugs/bug8-autolayout.stories.tsx +22 -31
- package/src/stories/circuit-components/diode.stories.tsx +3 -1
- package/src/stories/circuit-components/resistor.stories.tsx +3 -1
- package/src/stories/component-drawing-example.stories.tsx +2 -2
- package/src/stories/led-circuit-react.stories.tsx +40 -45
- package/src/stories/net-alias.stories.tsx +1 -1
- package/src/stories/off-center-render.stories.tsx +6 -6
- package/src/stories/rotated-resistor.stories.tsx +1 -1
- package/src/stories/schematic-path.stories.tsx +1 -1
- package/src/stories/three-sided-bug.stories.tsx +8 -8
- package/src/pages/led-circuit.tsx +0 -96
- package/src/schematic-components/ProjectComponent.tsx +0 -70
- package/src/schematic-components/SchematicBox.tsx +0 -29
- package/src/schematic-components/SchematicBug.tsx +0 -90
- package/src/schematic-components/SchematicLine.tsx +0 -48
- package/src/schematic-components/SchematicPath.tsx +0 -51
- package/src/schematic-components/SchematicPort.tsx +0 -63
- package/src/schematic-components/SimpleCapacitor.tsx +0 -29
- package/src/schematic-components/SimpleDiode.tsx +0 -42
- package/src/schematic-components/SimpleGround.tsx +0 -30
- package/src/schematic-components/SimpleInductor.tsx +0 -29
- package/src/schematic-components/SimplePowerSource.tsx +0 -43
- package/src/schematic-components/SimpleResistor.tsx +0 -28
- package/src/stories/led-circuit-builder.stories.tsx +0 -104
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
// Kicad-2020 color scheme
|
|
2
|
+
export const colorMap = {
|
|
3
|
+
"3d_viewer": {
|
|
4
|
+
background_bottom: "rgb(102, 102, 128)",
|
|
5
|
+
background_top: "rgb(204, 204, 230)",
|
|
6
|
+
board: "rgb(51, 43, 23)",
|
|
7
|
+
copper: "rgb(179, 156, 0)",
|
|
8
|
+
silkscreen_bottom: "rgb(230, 230, 230)",
|
|
9
|
+
silkscreen_top: "rgb(230, 230, 230)",
|
|
10
|
+
soldermask: "rgb(20, 51, 36)",
|
|
11
|
+
solderpaste: "rgb(128, 128, 128)",
|
|
12
|
+
},
|
|
13
|
+
board: {
|
|
14
|
+
anchor: "rgb(255, 38, 226)",
|
|
15
|
+
aux_items: "rgb(255, 255, 255)",
|
|
16
|
+
b_adhes: "rgb(0, 0, 132)",
|
|
17
|
+
b_crtyd: "rgb(255, 38, 226)",
|
|
18
|
+
b_fab: "rgb(88, 93, 132)",
|
|
19
|
+
b_mask: "rgba(2, 255, 238, 0.400)",
|
|
20
|
+
b_paste: "rgb(0, 194, 194)",
|
|
21
|
+
b_silks: "rgb(232, 178, 167)",
|
|
22
|
+
background: "rgb(0, 16, 35)",
|
|
23
|
+
cmts_user: "rgb(89, 148, 220)",
|
|
24
|
+
copper: {
|
|
25
|
+
b: "rgb(77, 127, 196)",
|
|
26
|
+
f: "rgb(200, 52, 52)",
|
|
27
|
+
in1: "rgb(127, 200, 127)",
|
|
28
|
+
in10: "rgb(237, 124, 51)",
|
|
29
|
+
in11: "rgb(91, 195, 235)",
|
|
30
|
+
in12: "rgb(247, 111, 142)",
|
|
31
|
+
in13: "rgb(167, 165, 198)",
|
|
32
|
+
in14: "rgb(40, 204, 217)",
|
|
33
|
+
in15: "rgb(232, 178, 167)",
|
|
34
|
+
in16: "rgb(242, 237, 161)",
|
|
35
|
+
in17: "rgb(237, 124, 51)",
|
|
36
|
+
in18: "rgb(91, 195, 235)",
|
|
37
|
+
in19: "rgb(247, 111, 142)",
|
|
38
|
+
in2: "rgb(206, 125, 44)",
|
|
39
|
+
in20: "rgb(167, 165, 198)",
|
|
40
|
+
in21: "rgb(40, 204, 217)",
|
|
41
|
+
in22: "rgb(232, 178, 167)",
|
|
42
|
+
in23: "rgb(242, 237, 161)",
|
|
43
|
+
in24: "rgb(237, 124, 51)",
|
|
44
|
+
in25: "rgb(91, 195, 235)",
|
|
45
|
+
in26: "rgb(247, 111, 142)",
|
|
46
|
+
in27: "rgb(167, 165, 198)",
|
|
47
|
+
in28: "rgb(40, 204, 217)",
|
|
48
|
+
in29: "rgb(232, 178, 167)",
|
|
49
|
+
in3: "rgb(79, 203, 203)",
|
|
50
|
+
in30: "rgb(242, 237, 161)",
|
|
51
|
+
in4: "rgb(219, 98, 139)",
|
|
52
|
+
in5: "rgb(167, 165, 198)",
|
|
53
|
+
in6: "rgb(40, 204, 217)",
|
|
54
|
+
in7: "rgb(232, 178, 167)",
|
|
55
|
+
in8: "rgb(242, 237, 161)",
|
|
56
|
+
in9: "rgb(141, 203, 129)",
|
|
57
|
+
},
|
|
58
|
+
cursor: "rgb(255, 255, 255)",
|
|
59
|
+
drc: "rgb(194, 194, 194)",
|
|
60
|
+
drc_error: "rgba(215, 91, 107, 0.800)",
|
|
61
|
+
drc_exclusion: "rgb(255, 255, 255)",
|
|
62
|
+
drc_warning: "rgba(255, 208, 66, 0.902)",
|
|
63
|
+
dwgs_user: "rgb(194, 194, 194)",
|
|
64
|
+
eco1_user: "rgb(180, 219, 210)",
|
|
65
|
+
eco2_user: "rgb(216, 200, 82)",
|
|
66
|
+
edge_cuts: "rgb(208, 210, 205)",
|
|
67
|
+
f_adhes: "rgb(132, 0, 132)",
|
|
68
|
+
f_crtyd: "rgb(255, 0, 245)",
|
|
69
|
+
f_fab: "rgb(175, 175, 175)",
|
|
70
|
+
f_mask: "rgba(216, 100, 255, 0.400)",
|
|
71
|
+
f_paste: "rgba(180, 160, 154, 0.902)",
|
|
72
|
+
f_silks: "rgb(242, 237, 161)",
|
|
73
|
+
footprint_text_back: "rgb(0, 0, 132)",
|
|
74
|
+
footprint_text_front: "rgb(194, 194, 194)",
|
|
75
|
+
footprint_text_invisible: "rgb(132, 132, 132)",
|
|
76
|
+
grid: "rgb(132, 132, 132)",
|
|
77
|
+
grid_axes: "rgb(194, 194, 194)",
|
|
78
|
+
margin: "rgb(255, 38, 226)",
|
|
79
|
+
microvia: "rgb(0, 132, 132)",
|
|
80
|
+
no_connect: "rgb(0, 0, 132)",
|
|
81
|
+
pad_back: "rgb(77, 127, 196)",
|
|
82
|
+
pad_front: "rgb(200, 52, 52)",
|
|
83
|
+
pad_plated_hole: "rgb(194, 194, 0)",
|
|
84
|
+
pad_through_hole: "rgb(227, 183, 46)",
|
|
85
|
+
plated_hole: "rgb(26, 196, 210)",
|
|
86
|
+
ratsnest: "rgba(245, 255, 213, 0.702)",
|
|
87
|
+
select_overlay: "rgb(4, 255, 67)",
|
|
88
|
+
through_via: "rgb(236, 236, 236)",
|
|
89
|
+
user_1: "rgb(194, 194, 194)",
|
|
90
|
+
user_2: "rgb(89, 148, 220)",
|
|
91
|
+
user_3: "rgb(180, 219, 210)",
|
|
92
|
+
user_4: "rgb(216, 200, 82)",
|
|
93
|
+
user_5: "rgb(194, 194, 194)",
|
|
94
|
+
user_6: "rgb(89, 148, 220)",
|
|
95
|
+
user_7: "rgb(180, 219, 210)",
|
|
96
|
+
user_8: "rgb(216, 200, 82)",
|
|
97
|
+
user_9: "rgb(232, 178, 167)",
|
|
98
|
+
via_blind_buried: "rgb(187, 151, 38)",
|
|
99
|
+
via_hole: "rgb(227, 183, 46)",
|
|
100
|
+
via_micro: "rgb(0, 132, 132)",
|
|
101
|
+
via_through: "rgb(236, 236, 236)",
|
|
102
|
+
worksheet: "rgb(200, 114, 171)",
|
|
103
|
+
},
|
|
104
|
+
gerbview: {
|
|
105
|
+
axes: "rgb(0, 0, 132)",
|
|
106
|
+
background: "rgb(0, 0, 0)",
|
|
107
|
+
dcodes: "rgb(255, 255, 255)",
|
|
108
|
+
grid: "rgb(132, 132, 132)",
|
|
109
|
+
layers: [
|
|
110
|
+
"rgb(132, 0, 0)",
|
|
111
|
+
"rgb(194, 194, 0)",
|
|
112
|
+
"rgb(194, 0, 194)",
|
|
113
|
+
"rgb(194, 0, 0)",
|
|
114
|
+
"rgb(0, 132, 132)",
|
|
115
|
+
"rgb(0, 132, 0)",
|
|
116
|
+
"rgb(0, 0, 132)",
|
|
117
|
+
"rgb(132, 132, 132)",
|
|
118
|
+
"rgb(132, 0, 132)",
|
|
119
|
+
"rgb(194, 194, 194)",
|
|
120
|
+
"rgb(132, 0, 132)",
|
|
121
|
+
"rgb(132, 0, 0)",
|
|
122
|
+
"rgb(132, 132, 0)",
|
|
123
|
+
"rgb(194, 194, 194)",
|
|
124
|
+
"rgb(0, 0, 132)",
|
|
125
|
+
"rgb(0, 132, 0)",
|
|
126
|
+
"rgb(132, 0, 0)",
|
|
127
|
+
"rgb(194, 194, 0)",
|
|
128
|
+
"rgb(194, 0, 194)",
|
|
129
|
+
"rgb(194, 0, 0)",
|
|
130
|
+
"rgb(0, 132, 132)",
|
|
131
|
+
"rgb(0, 132, 0)",
|
|
132
|
+
"rgb(0, 0, 132)",
|
|
133
|
+
"rgb(132, 132, 132)",
|
|
134
|
+
"rgb(132, 0, 132)",
|
|
135
|
+
"rgb(194, 194, 194)",
|
|
136
|
+
"rgb(132, 0, 132)",
|
|
137
|
+
"rgb(132, 0, 0)",
|
|
138
|
+
"rgb(132, 132, 0)",
|
|
139
|
+
"rgb(194, 194, 194)",
|
|
140
|
+
"rgb(0, 0, 132)",
|
|
141
|
+
"rgb(0, 132, 0)",
|
|
142
|
+
"rgb(132, 0, 0)",
|
|
143
|
+
"rgb(194, 194, 0)",
|
|
144
|
+
"rgb(194, 0, 194)",
|
|
145
|
+
"rgb(194, 0, 0)",
|
|
146
|
+
"rgb(0, 132, 132)",
|
|
147
|
+
"rgb(0, 132, 0)",
|
|
148
|
+
"rgb(0, 0, 132)",
|
|
149
|
+
"rgb(132, 132, 132)",
|
|
150
|
+
"rgb(132, 0, 132)",
|
|
151
|
+
"rgb(194, 194, 194)",
|
|
152
|
+
"rgb(132, 0, 132)",
|
|
153
|
+
"rgb(132, 0, 0)",
|
|
154
|
+
"rgb(132, 132, 0)",
|
|
155
|
+
"rgb(194, 194, 194)",
|
|
156
|
+
"rgb(0, 0, 132)",
|
|
157
|
+
"rgb(0, 132, 0)",
|
|
158
|
+
"rgb(132, 0, 0)",
|
|
159
|
+
"rgb(194, 194, 0)",
|
|
160
|
+
"rgb(194, 0, 194)",
|
|
161
|
+
"rgb(194, 0, 0)",
|
|
162
|
+
"rgb(0, 132, 132)",
|
|
163
|
+
"rgb(0, 132, 0)",
|
|
164
|
+
"rgb(0, 0, 132)",
|
|
165
|
+
"rgb(132, 132, 132)",
|
|
166
|
+
"rgb(132, 0, 132)",
|
|
167
|
+
"rgb(194, 194, 194)",
|
|
168
|
+
"rgb(132, 0, 132)",
|
|
169
|
+
"rgb(132, 0, 0)",
|
|
170
|
+
],
|
|
171
|
+
negative_objects: "rgb(132, 132, 132)",
|
|
172
|
+
worksheet: "rgb(0, 0, 132)",
|
|
173
|
+
},
|
|
174
|
+
meta: {
|
|
175
|
+
filename: "kicad_2020",
|
|
176
|
+
name: "KiCad 2020",
|
|
177
|
+
version: 2,
|
|
178
|
+
},
|
|
179
|
+
palette: [
|
|
180
|
+
"rgb(132, 0, 0)",
|
|
181
|
+
"rgb(194, 194, 0)",
|
|
182
|
+
"rgb(194, 0, 194)",
|
|
183
|
+
"rgb(194, 0, 0)",
|
|
184
|
+
"rgb(0, 132, 132)",
|
|
185
|
+
"rgb(0, 132, 0)",
|
|
186
|
+
"rgb(0, 0, 132)",
|
|
187
|
+
"rgb(132, 132, 132)",
|
|
188
|
+
"rgb(132, 0, 132)",
|
|
189
|
+
"rgb(194, 194, 194)",
|
|
190
|
+
"rgb(132, 0, 132)",
|
|
191
|
+
"rgb(132, 0, 0)",
|
|
192
|
+
"rgb(132, 132, 0)",
|
|
193
|
+
"rgb(194, 194, 194)",
|
|
194
|
+
"rgb(0, 0, 132)",
|
|
195
|
+
"rgb(0, 132, 0)",
|
|
196
|
+
],
|
|
197
|
+
schematic: {
|
|
198
|
+
aux_items: "rgb(46, 46, 46)",
|
|
199
|
+
background: "rgb(245, 241, 237)",
|
|
200
|
+
brightened: "rgb(255, 0, 255)",
|
|
201
|
+
bus: "rgb(0, 0, 132)",
|
|
202
|
+
bus_junction: "rgb(0, 0, 132)",
|
|
203
|
+
component_body: "rgb(255, 255, 194)",
|
|
204
|
+
component_outline: "rgb(132, 0, 0)",
|
|
205
|
+
cursor: "rgb(15, 15, 15)",
|
|
206
|
+
erc_error: "rgba(230, 9, 13, 0.800)",
|
|
207
|
+
erc_warning: "rgba(209, 146, 0, 0.800)",
|
|
208
|
+
fields: "rgb(132, 0, 132)",
|
|
209
|
+
grid: "rgb(181, 181, 181)",
|
|
210
|
+
grid_axes: "rgb(0, 0, 132)",
|
|
211
|
+
hidden: "rgb(194, 194, 194)",
|
|
212
|
+
junction: "rgb(0, 150, 0)",
|
|
213
|
+
label_global: "rgb(132, 0, 0)",
|
|
214
|
+
label_hier: "rgb(114, 86, 0)",
|
|
215
|
+
label_local: "rgb(15, 15, 15)",
|
|
216
|
+
net_name: "rgb(132, 132, 132)",
|
|
217
|
+
no_connect: "rgb(0, 0, 132)",
|
|
218
|
+
note: "rgb(0, 0, 194)",
|
|
219
|
+
override_item_colors: false,
|
|
220
|
+
pin: "rgb(132, 0, 0)",
|
|
221
|
+
pin_name: "rgb(0, 100, 100)",
|
|
222
|
+
pin_number: "rgb(169, 0, 0)",
|
|
223
|
+
reference: "rgb(0, 100, 100)",
|
|
224
|
+
shadow: "rgba(102, 179, 255, 0.800)",
|
|
225
|
+
sheet: "rgb(132, 0, 0)",
|
|
226
|
+
sheet_background: "rgba(253, 255, 231, 0.000)",
|
|
227
|
+
sheet_fields: "rgb(132, 0, 132)",
|
|
228
|
+
sheet_filename: "rgb(114, 86, 0)",
|
|
229
|
+
sheet_label: "rgb(0, 100, 100)",
|
|
230
|
+
sheet_name: "rgb(0, 100, 100)",
|
|
231
|
+
value: "rgb(0, 100, 100)",
|
|
232
|
+
wire: "rgb(0, 150, 0)",
|
|
233
|
+
worksheet: "rgb(132, 0, 0)",
|
|
234
|
+
},
|
|
235
|
+
}
|
|
236
|
+
|
|
@@ -1,30 +1,37 @@
|
|
|
1
|
-
import { useGlobalStore } from "lib/render-context"
|
|
2
|
-
import getSVGPathBounds from "lib/utils/get-svg-path-bounds"
|
|
3
|
-
import {
|
|
1
|
+
import { useGlobalStore } from "lib/render-context";
|
|
2
|
+
import getSVGPathBounds from "lib/utils/get-svg-path-bounds";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { applyToPoint, compose, scale, toSVG, translate } from "transformation-matrix";
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
interface PathProps {
|
|
7
|
+
type?: 'path';
|
|
8
|
+
strokeWidth: number;
|
|
9
|
+
stroke: string;
|
|
10
|
+
fill?: string;
|
|
11
|
+
d: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface CircleProps {
|
|
15
|
+
type: 'circle';
|
|
16
|
+
cx: number;
|
|
17
|
+
cy: number;
|
|
18
|
+
r: number;
|
|
19
|
+
strokeWidth: number;
|
|
20
|
+
stroke: string;
|
|
21
|
+
fill?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export type SVGElement = PathProps | CircleProps;
|
|
13
25
|
|
|
14
26
|
interface Props {
|
|
15
|
-
rotation: number
|
|
16
|
-
center: { x: number; y: number }
|
|
17
|
-
size: { width: number; height: number }
|
|
18
|
-
invertY?: boolean
|
|
19
|
-
shiftToBottom?: boolean
|
|
20
|
-
paths:
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
fill?: string
|
|
24
|
-
d: string
|
|
25
|
-
}>
|
|
26
|
-
zIndex?: number
|
|
27
|
-
hoverContent?: any
|
|
27
|
+
rotation: number;
|
|
28
|
+
center: { x: number; y: number };
|
|
29
|
+
size: { width: number; height: number };
|
|
30
|
+
invertY?: boolean;
|
|
31
|
+
shiftToBottom?: boolean;
|
|
32
|
+
paths: SVGElement[];
|
|
33
|
+
zIndex?: number;
|
|
34
|
+
hoverContent?: any;
|
|
28
35
|
}
|
|
29
36
|
|
|
30
37
|
export const SVGPathComponent = ({
|
|
@@ -37,136 +44,69 @@ export const SVGPathComponent = ({
|
|
|
37
44
|
shiftToBottom,
|
|
38
45
|
hoverContent,
|
|
39
46
|
}: Props) => {
|
|
40
|
-
const ct = useGlobalStore((s) => s.camera_transform)
|
|
41
|
-
const pathBounds = getSVGPathBounds(paths.
|
|
42
|
-
// Margin in SVG Space
|
|
43
|
-
const badRatio =
|
|
44
|
-
Math.abs(pathBounds.width / pathBounds.height - size.width / size.height) >
|
|
45
|
-
0.01
|
|
46
|
-
if (badRatio) {
|
|
47
|
-
// console.warn(
|
|
48
|
-
// `Ratio doesn't match for component. ${pathBounds.width}:${pathBounds.height} is not close to ${size.width}:${size.height}`
|
|
49
|
-
// )
|
|
50
|
-
}
|
|
51
|
-
// pathBounds.height = Math.max(pathBounds.height, 0.01)
|
|
52
|
-
// pathBounds.width = Math.max(pathBounds.width, 0.01)
|
|
53
|
-
|
|
54
|
-
// Three sizes:
|
|
55
|
-
// pathBound size (the size of the path in "d")
|
|
56
|
-
// innerSize (the screen-space size of the path)
|
|
57
|
-
// fullSize (the screen-space size of the svg element, innerSize plus padding)
|
|
58
|
-
|
|
59
|
-
const padding = {
|
|
60
|
-
x: 0,
|
|
61
|
-
y: 0,
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const absoluteCenter = applyToPoint(ct, center)
|
|
47
|
+
const ct = useGlobalStore((s) => s.camera_transform);
|
|
48
|
+
const pathBounds = getSVGPathBounds(paths.filter((p): p is PathProps => p.type !== 'circle').map(p => p.d));
|
|
65
49
|
|
|
50
|
+
const padding = { x: 0, y: 0 };
|
|
51
|
+
const absoluteCenter = applyToPoint(ct, center);
|
|
66
52
|
const innerSize = {
|
|
67
53
|
width: size.width * ct.a,
|
|
68
54
|
height: size.height * Math.abs(ct.d),
|
|
69
|
-
}
|
|
70
|
-
|
|
55
|
+
};
|
|
71
56
|
const fullSize = {
|
|
72
57
|
width: innerSize.width + padding.x * 2,
|
|
73
58
|
height: innerSize.height + padding.y * 2,
|
|
74
|
-
}
|
|
59
|
+
};
|
|
75
60
|
|
|
76
|
-
const [hovering, setHovering] = useState(false)
|
|
61
|
+
const [hovering, setHovering] = useState(false);
|
|
77
62
|
|
|
78
|
-
const svgLeft = absoluteCenter.x - fullSize.width / 2
|
|
79
|
-
const svgTop = absoluteCenter.y - fullSize.height / 2
|
|
63
|
+
const svgLeft = absoluteCenter.x - fullSize.width / 2;
|
|
64
|
+
const svgTop = absoluteCenter.y - fullSize.height / 2;
|
|
80
65
|
|
|
81
|
-
|
|
82
|
-
|
|
66
|
+
const preferredRatio = pathBounds.width === 0
|
|
67
|
+
? innerSize.height / pathBounds.height
|
|
68
|
+
: innerSize.width / pathBounds.width;
|
|
83
69
|
|
|
84
|
-
// console.log(
|
|
85
|
-
// pathBounds,
|
|
86
|
-
// fullSize,
|
|
87
|
-
// fullSize.width / pathBounds.width,
|
|
88
|
-
// fullSize.height / pathBounds.height
|
|
89
|
-
// )
|
|
90
|
-
const preferredRatio =
|
|
91
|
-
pathBounds.width === 0
|
|
92
|
-
? innerSize.height / pathBounds.height
|
|
93
|
-
: innerSize.width / pathBounds.width
|
|
94
70
|
const svgToScreen = compose(
|
|
95
|
-
// translate(0, 0)
|
|
96
71
|
scale(
|
|
97
|
-
pathBounds.width === 0
|
|
98
|
-
|
|
99
|
-
: fullSize.width / pathBounds.width,
|
|
100
|
-
pathBounds.height === 0
|
|
101
|
-
? preferredRatio
|
|
102
|
-
: fullSize.height / pathBounds.height
|
|
72
|
+
pathBounds.width === 0 ? preferredRatio : fullSize.width / pathBounds.width,
|
|
73
|
+
pathBounds.height === 0 ? preferredRatio : fullSize.height / pathBounds.height,
|
|
103
74
|
),
|
|
104
|
-
translate(-pathBounds.minX, -pathBounds.minY)
|
|
105
|
-
|
|
106
|
-
)
|
|
107
|
-
// console.log(svgToScreen)
|
|
108
|
-
// console.log(toSVG(svgToScreen))
|
|
109
|
-
// console.log(paths[0].d)
|
|
110
|
-
// translate(..., ...),
|
|
75
|
+
translate(-pathBounds.minX, -pathBounds.minY),
|
|
76
|
+
);
|
|
111
77
|
|
|
112
78
|
return (
|
|
113
|
-
|
|
114
|
-
{
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
79
|
+
<svg
|
|
80
|
+
onMouseOver={() => setHovering(Boolean(hoverContent))}
|
|
81
|
+
onMouseOut={() => setHovering(false)}
|
|
82
|
+
style={{
|
|
83
|
+
position: "absolute",
|
|
84
|
+
cursor: hovering ? "pointer" : undefined,
|
|
85
|
+
zIndex,
|
|
86
|
+
transform: [
|
|
87
|
+
invertY ? "scale(1, 1)" : "scale(1, -1)",
|
|
88
|
+
shiftToBottom ? "translate(0, 100%)" : "",
|
|
89
|
+
rotation === 0 ? "" : `rotate(${rotation}deg)`,
|
|
90
|
+
].join(" "),
|
|
91
|
+
left: svgLeft,
|
|
92
|
+
top: svgTop,
|
|
93
|
+
}}
|
|
94
|
+
overflow="visible"
|
|
95
|
+
width={fullSize.width}
|
|
96
|
+
height={fullSize.height}
|
|
97
|
+
>
|
|
98
|
+
{paths.map((p, i) =>
|
|
99
|
+
p.type === 'circle' ? (
|
|
100
|
+
<circle
|
|
101
|
+
key={i}
|
|
102
|
+
cx={p.cx}
|
|
103
|
+
cy={p.cy}
|
|
104
|
+
r={p.r}
|
|
105
|
+
fill={p.fill ?? "none"}
|
|
106
|
+
strokeWidth={1.5 * (p.strokeWidth || 1)}
|
|
107
|
+
stroke={p.stroke || "red"}
|
|
128
108
|
/>
|
|
129
|
-
|
|
130
|
-
style={{
|
|
131
|
-
position: "absolute",
|
|
132
|
-
left: svgLeft + fullSize.width + 10,
|
|
133
|
-
pointerEvents: "none",
|
|
134
|
-
zIndex: 1000,
|
|
135
|
-
color: "red",
|
|
136
|
-
mixBlendMode: "difference",
|
|
137
|
-
top: svgTop,
|
|
138
|
-
fontFamily: "monospace",
|
|
139
|
-
fontSize: 14,
|
|
140
|
-
}}
|
|
141
|
-
>
|
|
142
|
-
{hoverContent}
|
|
143
|
-
</div>
|
|
144
|
-
</>
|
|
145
|
-
)}
|
|
146
|
-
<svg
|
|
147
|
-
onMouseOver={() => setHovering(Boolean(hoverContent))}
|
|
148
|
-
onMouseOut={() => setHovering(false)}
|
|
149
|
-
style={{
|
|
150
|
-
position: "absolute",
|
|
151
|
-
// backgroundColor: hovering ? "rgba(0, 0, 255, 0.5)" : "transparent",
|
|
152
|
-
cursor: hovering ? "pointer" : undefined,
|
|
153
|
-
zIndex,
|
|
154
|
-
transform: [
|
|
155
|
-
invertY ? "scale(1, 1)" : "scale(1, -1)", // TODO based on ct.d
|
|
156
|
-
shiftToBottom ? "translate(0, 100%)" : "",
|
|
157
|
-
rotation === 0 ? "" : `rotate(${rotation}rad)`,
|
|
158
|
-
].join(" "),
|
|
159
|
-
left: svgLeft,
|
|
160
|
-
top: svgTop,
|
|
161
|
-
// overflow: "hidden",
|
|
162
|
-
// backgroundColor: badRatio ? "rgba(255, 0, 0, 0.1)" : "transparent",
|
|
163
|
-
// backgroundColor: "rgba(255, 0, 0, 0.1)",
|
|
164
|
-
}}
|
|
165
|
-
overflow="visible"
|
|
166
|
-
width={fullSize.width}
|
|
167
|
-
height={fullSize.height}
|
|
168
|
-
>
|
|
169
|
-
{paths.map((p, i) => (
|
|
109
|
+
) : (
|
|
170
110
|
<path
|
|
171
111
|
key={i}
|
|
172
112
|
transform={toSVG(svgToScreen)}
|
|
@@ -174,12 +114,12 @@ export const SVGPathComponent = ({
|
|
|
174
114
|
strokeLinecap="round"
|
|
175
115
|
strokeWidth={1.5 * (p.strokeWidth || 1)}
|
|
176
116
|
stroke={p.stroke || "red"}
|
|
177
|
-
d={p.d}
|
|
117
|
+
d={p.d || ""}
|
|
178
118
|
/>
|
|
179
|
-
)
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
)
|
|
183
|
-
}
|
|
119
|
+
)
|
|
120
|
+
)}
|
|
121
|
+
</svg>
|
|
122
|
+
);
|
|
123
|
+
};
|
|
184
124
|
|
|
185
|
-
export default SVGPathComponent
|
|
125
|
+
export default SVGPathComponent;
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { AnyCircuitElement, SchematicPort as OriginalSchematicPort, SchematicComponent } from "circuit-json";
|
|
2
|
+
import * as Type from "lib/types";
|
|
3
|
+
import { colorMap } from "lib/utils/colors";
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import SVGPathComponent from "./SVGPathComponent";
|
|
6
|
+
import SchematicText from "./SchematicText";
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
component: {
|
|
10
|
+
source: Type.SimpleBug;
|
|
11
|
+
schematic: SchematicComponent;
|
|
12
|
+
allElements: AnyCircuitElement[];
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
type ExtendedCenter = OriginalSchematicPort['center'] & {
|
|
17
|
+
side: "left" | "right" | "top" | "bottom";
|
|
18
|
+
pinNumber: number;
|
|
19
|
+
distanceFromEdge: number;
|
|
20
|
+
trueIndex: number;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
type SchematicPort = Omit<OriginalSchematicPort, 'center'> & {
|
|
24
|
+
center: ExtendedCenter;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const SchematicChip: React.FC<Props> = ({ component: { source, schematic, allElements } }) => {
|
|
28
|
+
const { center, size, rotation, schematic_component_id } = schematic;
|
|
29
|
+
const { manufacturerPartNumber, name } = source;
|
|
30
|
+
const chipWidth = size.width;
|
|
31
|
+
const chipHeight = size.height;
|
|
32
|
+
|
|
33
|
+
const paths: Array<{type?: 'path' | 'circle', strokeWidth: number, stroke: string, fill?: string, d?: string, cx?: number, cy?: number, r?: number}> = [];
|
|
34
|
+
|
|
35
|
+
// Main chip rectangle
|
|
36
|
+
paths.push({
|
|
37
|
+
type: 'path',
|
|
38
|
+
strokeWidth: 0.02,
|
|
39
|
+
stroke: colorMap.schematic.component_outline,
|
|
40
|
+
fill: colorMap.schematic.component_body,
|
|
41
|
+
d: `M ${-chipWidth / 2},${-chipHeight / 2} h ${chipWidth} v ${chipHeight} h ${-chipWidth} Z`,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const schematicPorts = allElements.filter(
|
|
45
|
+
(item): item is SchematicPort =>
|
|
46
|
+
item.type === "schematic_port" &&
|
|
47
|
+
item.schematic_component_id === schematic_component_id
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const portLength = 0.2;
|
|
51
|
+
const circleRadius = 0.05;
|
|
52
|
+
const labelOffset = 0.1;
|
|
53
|
+
|
|
54
|
+
const pinLabels: Array<{x: number, y: number, text: string, anchor: string}> = [];
|
|
55
|
+
|
|
56
|
+
schematicPorts.forEach((port) => {
|
|
57
|
+
const { side, pinNumber, distanceFromEdge } = port.center;
|
|
58
|
+
let x = 0, y = 0, endX = 0, endY = 0;
|
|
59
|
+
let labelX = 0, labelY = 0;
|
|
60
|
+
let textAnchor = "middle";
|
|
61
|
+
|
|
62
|
+
switch (side) {
|
|
63
|
+
case "left":
|
|
64
|
+
x = -chipWidth / 2;
|
|
65
|
+
y = -chipHeight / 2 + distanceFromEdge;
|
|
66
|
+
endX = x - portLength;
|
|
67
|
+
endY = y;
|
|
68
|
+
labelX = endX;
|
|
69
|
+
labelY = y + labelOffset;
|
|
70
|
+
textAnchor = "end";
|
|
71
|
+
break;
|
|
72
|
+
case "right":
|
|
73
|
+
x = chipWidth / 2;
|
|
74
|
+
y = chipHeight / 2 - distanceFromEdge;
|
|
75
|
+
endX = x + portLength;
|
|
76
|
+
endY = y;
|
|
77
|
+
labelX = endX - labelOffset;
|
|
78
|
+
labelY = y + labelOffset;
|
|
79
|
+
textAnchor = "start";
|
|
80
|
+
break;
|
|
81
|
+
case "bottom":
|
|
82
|
+
x = -chipWidth / 2 + distanceFromEdge;
|
|
83
|
+
y = -chipHeight / 2;
|
|
84
|
+
endX = x;
|
|
85
|
+
endY = y - portLength;
|
|
86
|
+
labelX = x;
|
|
87
|
+
labelY = endY + labelOffset;
|
|
88
|
+
break;
|
|
89
|
+
case "top":
|
|
90
|
+
x = chipWidth / 2 - distanceFromEdge;
|
|
91
|
+
y = chipHeight / 2;
|
|
92
|
+
endX = x;
|
|
93
|
+
endY = y + portLength;
|
|
94
|
+
labelX = x;
|
|
95
|
+
labelY = endY + labelOffset;
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Port line
|
|
100
|
+
paths.push({
|
|
101
|
+
type: 'path',
|
|
102
|
+
strokeWidth: 0.02,
|
|
103
|
+
stroke: colorMap.schematic.component_outline,
|
|
104
|
+
d: `M ${x},${y} L ${endX},${endY}`,
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Port circle at the end of the line
|
|
108
|
+
paths.push({
|
|
109
|
+
type: 'circle',
|
|
110
|
+
cx: endX,
|
|
111
|
+
cy: endY,
|
|
112
|
+
r: circleRadius,
|
|
113
|
+
strokeWidth: 0.01,
|
|
114
|
+
stroke: colorMap.schematic.component_outline,
|
|
115
|
+
fill: colorMap.schematic.component_outline,
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Add pin label
|
|
119
|
+
if(pinNumber !== undefined) {
|
|
120
|
+
pinLabels.push({
|
|
121
|
+
x: labelX,
|
|
122
|
+
y: labelY,
|
|
123
|
+
text: `${pinNumber}`,
|
|
124
|
+
anchor: textAnchor
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
return (
|
|
130
|
+
<>
|
|
131
|
+
<SVGPathComponent
|
|
132
|
+
rotation={rotation}
|
|
133
|
+
center={center}
|
|
134
|
+
size={size}
|
|
135
|
+
paths={paths as any}
|
|
136
|
+
/>
|
|
137
|
+
{pinLabels.map((label, index) => (
|
|
138
|
+
<SchematicText
|
|
139
|
+
key={index}
|
|
140
|
+
schematic_text={{
|
|
141
|
+
anchor: label.anchor as any,
|
|
142
|
+
position: {
|
|
143
|
+
x: center.x + label.x,
|
|
144
|
+
y: center.y + label.y,
|
|
145
|
+
},
|
|
146
|
+
schematic_component_id: "SYNTHETIC",
|
|
147
|
+
schematic_text_id: `PIN_LABEL_${index}`,
|
|
148
|
+
text: label.text,
|
|
149
|
+
type: "schematic_text",
|
|
150
|
+
}}
|
|
151
|
+
/>
|
|
152
|
+
))}
|
|
153
|
+
<SchematicText
|
|
154
|
+
schematic_text={{
|
|
155
|
+
anchor: "center",
|
|
156
|
+
position: {
|
|
157
|
+
x: center.x,
|
|
158
|
+
y: center.y - chipHeight / 2 - 0.2,
|
|
159
|
+
},
|
|
160
|
+
schematic_component_id: "SYNTHETIC",
|
|
161
|
+
schematic_text_id: "SYNTHETIC_MPN",
|
|
162
|
+
text: manufacturerPartNumber,
|
|
163
|
+
type: "schematic_text",
|
|
164
|
+
}}
|
|
165
|
+
/>
|
|
166
|
+
<SchematicText
|
|
167
|
+
schematic_text={{
|
|
168
|
+
anchor: "center",
|
|
169
|
+
position: {
|
|
170
|
+
x: center.x,
|
|
171
|
+
y: center.y + chipHeight / 2 + 0.2,
|
|
172
|
+
},
|
|
173
|
+
schematic_component_id: "SYNTHETIC",
|
|
174
|
+
schematic_text_id: "SYNTHETIC_NAME",
|
|
175
|
+
text: name,
|
|
176
|
+
type: "schematic_text",
|
|
177
|
+
}}
|
|
178
|
+
/>
|
|
179
|
+
</>
|
|
180
|
+
);
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
export default SchematicChip;
|