@tscircuit/schematic-viewer 1.2.6 → 1.2.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/schematic-viewer",
3
- "version": "1.2.6",
3
+ "version": "1.2.8",
4
4
  "main": "dist/index.js",
5
5
  "license": "MIT",
6
6
  "repository": "tscircuit/schematic-viewer",
@@ -32,8 +32,8 @@
32
32
  "@storybook/nextjs": "^7.4.0",
33
33
  "@storybook/react": "^7.4.0",
34
34
  "@storybook/testing-library": "^0.0.14-next.2",
35
- "@tscircuit/builder": "^1.5.88",
36
- "@tscircuit/react-fiber": "^1.1.1",
35
+ "@tscircuit/builder": "^1.5.89",
36
+ "@tscircuit/react-fiber": "^1.1.8",
37
37
  "@tscircuit/routing": "^1.3.0",
38
38
  "@tscircuit/table-viewer": "^0.0.6",
39
39
  "@types/node": "^18.6.0",
@@ -58,6 +58,8 @@
58
58
  "zustand": "^4.0.0"
59
59
  },
60
60
  "dependencies": {
61
+ "@tscircuit/soup": "^0.0.7",
62
+ "convert-units": "^2.3.4",
61
63
  "react-error-boundary": "^4.0.4",
62
64
  "react-supergrid": "^1.0.10",
63
65
  "use-mouse-matrix-transform": "^1.1.12"
package/src/Schematic.tsx CHANGED
@@ -82,6 +82,7 @@ export const Schematic = ({
82
82
  (elmBounds.height ?? 0) / height,
83
83
  100
84
84
  )
85
+ // console.log(elements)
85
86
  setElements(elements)
86
87
  setProject(createProjectFromElements(elements))
87
88
  setTransform(
@@ -3,7 +3,7 @@ export const directionToVec = (direction: "up" | "down" | "left" | "right") => {
3
3
  else if (direction === "down") return { x: 0, y: -1 }
4
4
  else if (direction === "left") return { x: -1, y: 0 }
5
5
  else if (direction === "right") return { x: 1, y: 0 }
6
- else throw new Error("Invalid direction")
6
+ else throw new Error(`Invalid direction "${direction}"`)
7
7
  }
8
8
 
9
9
  export const vecToDirection = ({ x, y }: { x: number; y: number }) => {
@@ -2,7 +2,14 @@ import { useCameraTransform } from "lib/render-context"
2
2
  import getSVGPathBounds from "lib/utils/get-svg-path-bounds"
3
3
  import { useCallback, useState } from "react"
4
4
 
5
- import { applyToPoint } from "transformation-matrix"
5
+ import {
6
+ applyToPoint,
7
+ toSVG,
8
+ inverse,
9
+ compose,
10
+ translate,
11
+ scale,
12
+ } from "transformation-matrix"
6
13
 
7
14
  interface Props {
8
15
  rotation: number
@@ -41,23 +48,66 @@ export const SVGPathComponent = ({
41
48
  // `Ratio doesn't match for component. ${pathBounds.width}:${pathBounds.height} is not close to ${size.width}:${size.height}`
42
49
  // )
43
50
  }
44
- pathBounds.height = Math.max(pathBounds.height, 0.01)
45
- pathBounds.width = Math.max(pathBounds.width, 0.01)
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
+
46
64
  const absoluteCenter = applyToPoint(ct, center)
47
- const actualAbsWidth = size.width * ct.a
48
- const actualAbsHeight = size.height * Math.abs(ct.d)
49
- const absoluteSize = {
50
- width: Math.max(1, actualAbsWidth),
51
- height: Math.max(1, actualAbsHeight),
65
+
66
+ const innerSize = {
67
+ width: size.width * ct.a,
68
+ height: size.height * Math.abs(ct.d),
69
+ }
70
+
71
+ const fullSize = {
72
+ width: innerSize.width + padding.x * 2,
73
+ height: innerSize.height + padding.y * 2,
52
74
  }
53
- console.log(absoluteSize, pathBounds)
54
75
 
55
76
  const [hovering, setHovering] = useState(false)
56
77
 
57
- const svgLeft = absoluteCenter.x - absoluteSize.width / 2
58
- const svgTop = absoluteCenter.y - absoluteSize.height / 2
78
+ const svgLeft = absoluteCenter.x - fullSize.width / 2
79
+ const svgTop = absoluteCenter.y - fullSize.height / 2
59
80
 
60
- const viewBox = `${pathBounds.minX} ${pathBounds.minY} ${pathBounds.width} ${pathBounds.height}`
81
+ // const viewBox = `${pathBounds.minX} ${pathBounds.minY} ${pathBounds.width} ${pathBounds.height}`
82
+ // const viewBox2 = `${svgLeft} ${svgTctualAbsWidth} ${actualAbsHeight}`
83
+
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
+ const svgToScreen = compose(
95
+ // translate(0, 0)
96
+ scale(
97
+ pathBounds.width === 0
98
+ ? preferredRatio
99
+ : fullSize.width / pathBounds.width,
100
+ pathBounds.height === 0
101
+ ? preferredRatio
102
+ : fullSize.height / pathBounds.height
103
+ ),
104
+ translate(-pathBounds.minX, -pathBounds.minY)
105
+ // translate(center.x, center.y)
106
+ )
107
+ // console.log(svgToScreen)
108
+ // console.log(toSVG(svgToScreen))
109
+ // console.log(paths[0].d)
110
+ // translate(..., ...),
61
111
 
62
112
  return (
63
113
  <>
@@ -66,11 +116,11 @@ export const SVGPathComponent = ({
66
116
  <div
67
117
  style={{
68
118
  position: "absolute",
69
- left: svgLeft - 4,
70
- top: svgTop - 4,
119
+ left: svgLeft - 6,
120
+ top: svgTop - 6,
71
121
  pointerEvents: "none",
72
- width: actualAbsWidth + 8,
73
- height: actualAbsHeight + 8,
122
+ width: fullSize.width + 12,
123
+ height: fullSize.height + 12,
74
124
  border: "1px red solid",
75
125
  mixBlendMode: "difference",
76
126
  zIndex: 1000,
@@ -79,7 +129,7 @@ export const SVGPathComponent = ({
79
129
  <div
80
130
  style={{
81
131
  position: "absolute",
82
- left: svgLeft + actualAbsWidth + 10,
132
+ left: svgLeft + fullSize.width + 10,
83
133
  pointerEvents: "none",
84
134
  zIndex: 1000,
85
135
  color: "red",
@@ -108,19 +158,21 @@ export const SVGPathComponent = ({
108
158
  ].join(" "),
109
159
  left: svgLeft,
110
160
  top: svgTop,
111
- // backgroundColor: badRatio ? "rgba(255, 0, 0, 0.5)" : "transparent",
161
+ // overflow: "hidden",
162
+ // backgroundColor: badRatio ? "rgba(255, 0, 0, 0.1)" : "transparent",
163
+ // backgroundColor: "rgba(255, 0, 0, 0.1)",
112
164
  }}
113
165
  overflow="visible"
114
- width={absoluteSize.width}
115
- height={absoluteSize.height}
116
- viewBox={viewBox}
166
+ width={fullSize.width}
167
+ height={fullSize.height}
117
168
  >
118
169
  {paths.map((p, i) => (
119
170
  <path
120
171
  key={i}
172
+ transform={toSVG(svgToScreen)}
121
173
  fill={p.fill ?? "none"}
122
174
  strokeLinecap="round"
123
- strokeWidth={2 * (p.strokeWidth || 1)}
175
+ strokeWidth={1.5 * (p.strokeWidth || 1)}
124
176
  stroke={p.stroke || "red"}
125
177
  d={p.d}
126
178
  />
@@ -0,0 +1,76 @@
1
+ import { useCameraTransform } from "lib/render-context"
2
+ import getSVGPathBounds from "lib/utils/get-svg-path-bounds"
3
+ import { useCallback, useState } from "react"
4
+
5
+ import {
6
+ applyToPoint,
7
+ toSVG,
8
+ inverse,
9
+ compose,
10
+ translate,
11
+ scale,
12
+ } from "transformation-matrix"
13
+
14
+ 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: Array<{
21
+ strokeWidth: number
22
+ stroke: string
23
+ fill?: string
24
+ d: string
25
+ }>
26
+ zIndex?: number
27
+ hoverContent?: any
28
+ }
29
+
30
+ export const SVGPathComponent2 = ({
31
+ size,
32
+ center,
33
+ rotation,
34
+ paths,
35
+ zIndex,
36
+ invertY,
37
+ shiftToBottom,
38
+ hoverContent,
39
+ }: Props) => {
40
+ const ct = useCameraTransform()
41
+ const pathBounds = getSVGPathBounds(paths.map((p) => p.d))
42
+ // Margin in SVG Space
43
+
44
+ return (
45
+ <svg
46
+ style={{
47
+ position: "absolute",
48
+ left: 0,
49
+ top: 0,
50
+ right: 0,
51
+ bottom: 0,
52
+ // backgroundColor: hovering ? "rgba(0, 0, 255, 0.5)" : "transparent",
53
+ pointerEvents: "none",
54
+ zIndex,
55
+ // overflow: "hidden",
56
+ // backgroundColor: badRatio ? "rgba(255, 0, 0, 0.1)" : "transparent",
57
+ // backgroundColor: "rgba(255, 0, 0, 0.1)",
58
+ }}
59
+ overflow="visible"
60
+ >
61
+ {paths.map((p, i) => (
62
+ <path
63
+ key={i}
64
+ transform={toSVG(ct)}
65
+ fill={p.fill ?? "none"}
66
+ strokeLinecap="round"
67
+ strokeWidth={1.5 * (p.strokeWidth || 1)}
68
+ stroke={p.stroke || "red"}
69
+ d={p.d}
70
+ />
71
+ ))}
72
+ </svg>
73
+ )
74
+ }
75
+
76
+ export default SVGPathComponent2
@@ -22,8 +22,8 @@ export const SchematicLine = ({ line: { schematic } }: Props) => {
22
22
  path.lineTo(x2, y2)
23
23
  const d = path.toString()
24
24
  const pathBounds = getSVGPathBounds(d)
25
- pathBounds.height = Math.max(pathBounds.height, 1)
26
- pathBounds.width = Math.max(pathBounds.width, 1)
25
+ // pathBounds.height = Math.max(pathBounds.height, 1)
26
+ // pathBounds.width = Math.max(pathBounds.width, 1)
27
27
  const center = {
28
28
  x: pathBounds.minX + pathBounds.width / 2,
29
29
  y: pathBounds.minY + pathBounds.height / 2,
@@ -19,6 +19,7 @@ export const SchematicPort = ({
19
19
  source_port?.name ?? source_port?.pin_number
20
20
  }`
21
21
  : `.${source_port?.name ?? source_port?.pin_number}`
22
+ const vec = directionToVec(schematic.facing_direction)
22
23
  return (
23
24
  <Component.SVGPathComponent
24
25
  rotation={0}
@@ -36,7 +37,10 @@ export const SchematicPort = ({
36
37
  </div>
37
38
  }
38
39
  center={schematic.center}
39
- size={{ width: 0.2, height: 0.2 }}
40
+ size={{
41
+ width: 0.2 + Math.abs(vec.x) * 0.04,
42
+ height: 0.2 + Math.abs(vec.y) * 0.04,
43
+ }}
40
44
  zIndex={10}
41
45
  paths={[
42
46
  {
@@ -48,9 +52,7 @@ export const SchematicPort = ({
48
52
  ? {
49
53
  stroke: "blue",
50
54
  strokeWidth: 0.5,
51
- d: `M 5 5 l ${directionToVec(schematic.facing_direction).x * 7} ${
52
- directionToVec(schematic.facing_direction).y * 7
53
- }`,
55
+ d: `M 5 5 l ${vec.x * 7} ${vec.y * 7}`,
54
56
  }
55
57
  : null,
56
58
  ].filter(Boolean)}
@@ -3,6 +3,7 @@ import SVGPathComponent from "./SVGPathComponent"
3
3
  import Path from "svg-path-generator"
4
4
  import getSVGPathBounds from "lib/utils/get-svg-path-bounds"
5
5
  import RenderError from "./RenderError"
6
+ import SVGPathComponent2 from "./SVGPathComponent2"
6
7
 
7
8
  interface Props {
8
9
  trace: {
@@ -32,7 +33,7 @@ export const SchematicTrace = ({ trace: { source, schematic } }: Props) => {
32
33
  y: pathBounds.minY + pathBounds.height / 2,
33
34
  }
34
35
  return (
35
- <SVGPathComponent
36
+ <SVGPathComponent2
36
37
  rotation={0}
37
38
  center={center}
38
39
  size={pathBounds}
@@ -18,8 +18,8 @@ export const SimpleCapacitor = ({
18
18
  size={schematic.size}
19
19
  paths={[
20
20
  { stroke: "red", strokeWidth: 1, d: "M 0 15 l 12 0" },
21
- { stroke: "red", strokeWidth: 2, d: "M 12 0 l 0 30" },
22
- { stroke: "red", strokeWidth: 2, d: "M 18 0 l 0 30" },
21
+ { stroke: "red", strokeWidth: 1, d: "M 12 0 l 0 30" },
22
+ { stroke: "red", strokeWidth: 1, d: "M 18 0 l 0 30" },
23
23
  { stroke: "red", strokeWidth: 1, d: "M 18 15 l 12 0" },
24
24
  ]}
25
25
  />
@@ -23,6 +23,18 @@ export const SimplePowerSource = ({
23
23
  strokeWidth: 1,
24
24
  d: "M 0 -17 L 0 -3 M -8 3 L 8 3 M 0 17 L 0 3 M -12 -3 L 12 -3",
25
25
  },
26
+ // positive symbol
27
+ {
28
+ stroke: "red",
29
+ strokeWidth: 0.5,
30
+ d: "M 8 -9 L 8 -6 M 9.5 -7.5 L 6.5 -7.5",
31
+ },
32
+ // negative symbol
33
+ {
34
+ stroke: "red",
35
+ strokeWidth: 0.5,
36
+ d: "M 9.5 7.5 L 6.5 7.5",
37
+ },
26
38
  ]}
27
39
  />
28
40
  )
@@ -0,0 +1,18 @@
1
+ import { useResistor } from "@tscircuit/react-fiber"
2
+ import { Schematic } from "../../Schematic"
3
+
4
+ export const Bug3ScalingTrace = () => {
5
+ const R1 = useResistor("R1", { resistance: "10" })
6
+ const R2 = useResistor("R2", { resistance: "1k" })
7
+ return (
8
+ <Schematic style={{ height: 500 }}>
9
+ <R1 schX={2} schY={1} />
10
+ <R2 schRotation="90deg" schX={0} schY={3} left={R1.left} />
11
+ </Schematic>
12
+ )
13
+ }
14
+
15
+ export default {
16
+ title: "Bugs/Bug3ScalingTrace",
17
+ component: Bug3ScalingTrace,
18
+ }
@@ -0,0 +1,18 @@
1
+ import { useResistor } from "@tscircuit/react-fiber"
2
+ import { Schematic } from "../../Schematic"
3
+
4
+ export const Bug4SchematicLine = () => {
5
+ return (
6
+ <Schematic style={{ height: 500 }}>
7
+ {/* <resistor name="R1" resistance="10" schX={2} schY={1} /> */}
8
+ <component name="K1" schX={0} schY={0}>
9
+ <schematicline x1={0} y1={0} x2={0} y2={2} />
10
+ </component>
11
+ </Schematic>
12
+ )
13
+ }
14
+
15
+ export default {
16
+ title: "Bugs/Bug4SchematicLine",
17
+ component: Bug4SchematicLine,
18
+ }
@@ -0,0 +1,15 @@
1
+ import { useResistor } from "@tscircuit/react-fiber"
2
+ import { Schematic } from "../../Schematic"
3
+
4
+ export const Bug5SchematicLine = () => {
5
+ return (
6
+ <Schematic style={{ height: 500 }}>
7
+ <diode name="D1" />
8
+ </Schematic>
9
+ )
10
+ }
11
+
12
+ export default {
13
+ title: "Bugs/Bug5SchematicLine",
14
+ component: Bug5SchematicLine,
15
+ }
@@ -0,0 +1,54 @@
1
+ import { Schematic } from "../../Schematic"
2
+
3
+ export const Bug6TraceScaling = () => {
4
+ return (
5
+ <Schematic style={{ height: 500 }}>
6
+ <resistor name="R1" resistance="10 ohm" schX={2} schY={1} />
7
+ {/* <powersource voltage="5V" schX={1} schY={2} name="main_power" /> */}
8
+ <resistor resistance="1k" schX={1} schY={2} name="main_power" />
9
+ {/* <trace path={[".main_power > port.negative", ".R1 > port.left"]} /> */}
10
+ <trace path={[".main_power > port.right", ".R1 > port.left"]} />
11
+ </Schematic>
12
+ // <Schematic
13
+ // style={{ height: 500 }}
14
+ // soup={[
15
+ // {
16
+ // type: "source_trace",
17
+ // source_trace_id: "source_trace_0",
18
+ // },
19
+ // {
20
+ // type: "schematic_trace",
21
+ // source_trace_id: "source_trace_0",
22
+ // schematic_trace_id: "schematic_trace_0",
23
+ // edges: [
24
+ // {
25
+ // from: {
26
+ // x: 1,
27
+ // y: 1.4000000000000001,
28
+ // },
29
+ // to: {
30
+ // x: 1,
31
+ // y: 1,
32
+ // },
33
+ // },
34
+ // {
35
+ // from: {
36
+ // x: 1,
37
+ // y: 1,
38
+ // },
39
+ // to: {
40
+ // x: 1.4000000000000001,
41
+ // y: 1,
42
+ // },
43
+ // },
44
+ // ],
45
+ // },
46
+ // ]}
47
+ // />
48
+ )
49
+ }
50
+
51
+ export default {
52
+ title: "Bugs/Bug6TraceScaling",
53
+ component: Bug6TraceScaling,
54
+ }
@@ -0,0 +1,14 @@
1
+ import { Schematic } from "../Schematic"
2
+
3
+ export const Resistor = () => {
4
+ return (
5
+ <Schematic style={{ height: 500 }}>
6
+ <resistor name="R1" resistance="10 ohm" schX={2} schY={1} />
7
+ </Schematic>
8
+ )
9
+ }
10
+
11
+ export default {
12
+ title: "Resistor",
13
+ component: Resistor,
14
+ }
@@ -0,0 +1,21 @@
1
+ import { Schematic } from "../Schematic"
2
+
3
+ export const RotatedResistor = () => {
4
+ return (
5
+ <Schematic style={{ height: 500 }}>
6
+ <resistor
7
+ name="R1"
8
+ resistance="10 ohm"
9
+ schX={2}
10
+ schY={1}
11
+ schRotation="90deg"
12
+ rotation="90deg"
13
+ />
14
+ </Schematic>
15
+ )
16
+ }
17
+
18
+ export default {
19
+ title: "RotatedResistor",
20
+ component: RotatedResistor,
21
+ }