circuit-to-svg 0.0.17 → 0.0.18
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/dist/index.js +6 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -128,12 +128,6 @@ function circuitJsonToPcbSvg(soup) {
|
|
|
128
128
|
attributes: { id: "other-elements" },
|
|
129
129
|
children: otherElements
|
|
130
130
|
},
|
|
131
|
-
{
|
|
132
|
-
name: "g",
|
|
133
|
-
type: "element",
|
|
134
|
-
attributes: { id: "silkscreen" },
|
|
135
|
-
children: silkscreenElements
|
|
136
|
-
},
|
|
137
131
|
{
|
|
138
132
|
name: "g",
|
|
139
133
|
type: "element",
|
|
@@ -145,6 +139,12 @@ function circuitJsonToPcbSvg(soup) {
|
|
|
145
139
|
type: "element",
|
|
146
140
|
attributes: { id: "holes" },
|
|
147
141
|
children: holeElements
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
name: "g",
|
|
145
|
+
type: "element",
|
|
146
|
+
attributes: { id: "silkscreen" },
|
|
147
|
+
children: silkscreenElements
|
|
148
148
|
}
|
|
149
149
|
].filter((child) => child !== null)
|
|
150
150
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/lib/circuit-to-pcb-svg.ts","../src/lib/circuit-to-schematic-svg.ts"],"sourcesContent":["export * from \"./lib\";\n\n","import type { AnySoupElement } from \"@tscircuit/soup\"\nimport { type INode, stringify } from \"svgson\"\nimport { applyToPoint, compose, scale, translate } from \"transformation-matrix\"\n\ninterface SvgObject {\n name: string\n type: \"element\" | \"text\"\n attributes?: { [key: string]: string }\n children?: SvgObject[]\n value?: string\n}\n\ninterface PointObjectNotation {\n x: number\n y: number\n}\n\nfunction circuitJsonToPcbSvg(soup: AnySoupElement[]): string {\n let minX = Number.POSITIVE_INFINITY\n let minY = Number.POSITIVE_INFINITY\n let maxX = Number.NEGATIVE_INFINITY\n let maxY = Number.NEGATIVE_INFINITY\n\n // Process all elements to determine bounds\n for (const item of soup) {\n if (\"center\" in item && \"width\" in item && \"height\" in item) {\n updateBounds(item.center, item.width, item.height)\n } else if (\"x\" in item && \"y\" in item) {\n updateBounds({ x: item.x, y: item.y }, 0, 0)\n } else if (\"route\" in item) {\n updateTraceBounds(item.route)\n }\n }\n\n const padding = 1 // Reduced padding for tighter boundary\n const circuitWidth = maxX - minX + 2 * padding\n const circuitHeight = maxY - minY + 2 * padding\n\n const svgWidth = 800\n const svgHeight = 600\n const paths: PointObjectNotation[][] = []\n for (const item of soup) {\n if (\"route\" in item && item.route !== undefined) {\n paths.push(item.route as PointObjectNotation[])\n }\n }\n\n // Calculate scale factor to fit the circuit within the SVG, maintaining aspect ratio\n const scaleX = svgWidth / circuitWidth\n const scaleY = svgHeight / circuitHeight\n const scaleFactor = Math.min(scaleX, scaleY)\n\n // Calculate centering offsets\n const offsetX = (svgWidth - circuitWidth * scaleFactor) / 2\n const offsetY = (svgHeight - circuitHeight * scaleFactor) / 2\n\n const transform = compose(\n translate(\n offsetX - minX * scaleFactor + padding * scaleFactor,\n svgHeight - offsetY + minY * scaleFactor - padding * scaleFactor,\n ),\n scale(scaleFactor, -scaleFactor), // Flip in y-direction\n )\n\n const traceElements = soup\n .filter((item) => item.type === \"pcb_trace\")\n .map((item) => createSvgElement(item, transform))\n .filter((element) => element !== null)\n\n const holeElements = soup\n .filter((item) => item.type === \"pcb_plated_hole\")\n .map((item) => createSvgElement(item, transform))\n .filter((element) => element !== null)\n\n const silkscreenElements = soup\n .filter((item) => item.type === \"pcb_silkscreen_path\")\n .map((item) => createPcbSilkscreenPath(item, transform))\n .filter((element) => element !== null)\n\n const otherElements = soup\n .filter(\n (item) =>\n ![\"pcb_trace\", \"pcb_plated_hole\", \"pcb_silkscreen_path\"].includes(\n item.type,\n ),\n )\n .map((item) => createSvgElement(item, transform))\n .filter((element) => element !== null)\n\n let strokeWidth = String(0.05 * scaleFactor)\n\n for (const element of soup) {\n if (\"stroke_width\" in element) {\n strokeWidth = String(scaleFactor * element.stroke_width)\n break\n }\n }\n\n const svgObject: SvgObject = {\n name: \"svg\",\n type: \"element\",\n attributes: {\n xmlns: \"http://www.w3.org/2000/svg\",\n width: svgWidth.toString(),\n height: svgHeight.toString(),\n },\n children: [\n {\n name: \"style\",\n type: \"element\",\n children: [\n {\n type: \"text\",\n value: `\n .pcb-board { fill: #000; }\n .pcb-trace { stroke: rgb(200, 52, 52); stroke-width: ${strokeWidth}; fill: none; }\n .pcb-hole-outer { fill: rgb(200, 52, 52); }\n .pcb-hole-inner { fill: rgb(255, 38, 226); }\n .pcb-pad { fill: rgb(200, 52, 52); }\n .pcb-boundary { fill: none; stroke: #fff; stroke-width: 0.3; }\n .pcb-silkscreen { fill: none; }\n .pcb-silkscreen-top { stroke: #f2eda1; }\n .pcb-silkscreen-bottom { stroke: #f2eda1; }\n `,\n },\n ],\n },\n {\n name: \"rect\",\n type: \"element\",\n attributes: {\n class: \"pcb-board\",\n x: \"0\",\n y: \"0\",\n width: svgWidth.toString(),\n height: svgHeight.toString(),\n },\n },\n createPcbBoundary(transform, minX, minY, maxX, maxY),\n {\n name: \"g\",\n type: \"element\",\n attributes: { id: \"other-elements\" },\n children: otherElements,\n },\n {\n name: \"g\",\n type: \"element\",\n attributes: { id: \"silkscreen\" },\n children: silkscreenElements,\n },\n {\n name: \"g\",\n type: \"element\",\n attributes: { id: \"traces\" },\n children: traceElements,\n },\n {\n name: \"g\",\n type: \"element\",\n attributes: { id: \"holes\" },\n children: holeElements,\n },\n ].filter((child) => child !== null),\n }\n\n try {\n return stringify(svgObject as INode)\n } catch (error) {\n console.error(\"Error stringifying SVG object:\", error)\n throw error\n }\n\n function updateBounds(center: any, width: any, height: any) {\n const halfWidth = width / 2\n const halfHeight = height / 2\n minX = Math.min(minX, center.x - halfWidth)\n minY = Math.min(minY, center.y - halfHeight)\n maxX = Math.max(maxX, center.x + halfWidth)\n maxY = Math.max(maxY, center.y + halfHeight)\n }\n\n function updateTraceBounds(route: any[]) {\n for (const point of route) {\n minX = Math.min(minX, point.x)\n minY = Math.min(minY, point.y)\n maxX = Math.max(maxX, point.x)\n maxY = Math.max(maxY, point.y)\n }\n }\n}\n\nfunction createSvgElement(item: AnySoupElement, transform: any): any {\n switch (item.type) {\n case \"pcb_component\":\n return createPcbComponent(item, transform)\n case \"pcb_trace\":\n return createPcbTrace(item, transform)\n case \"pcb_plated_hole\":\n return createPcbHole(item, transform)\n case \"pcb_smtpad\":\n return createPcbSMTPad(item, transform)\n default:\n return null\n }\n}\n\nfunction createPcbComponent(component: any, transform: any): any {\n const { center, width, height, rotation = 0 } = component\n const [x, y] = applyToPoint(transform, [center.x, center.y])\n const scaledWidth = width * Math.abs(transform.a)\n const scaledHeight = height * Math.abs(transform.d)\n const transformStr = `translate(${x}, ${y}) rotate(${-rotation}) scale(1, -1)`\n\n return {\n name: \"g\",\n type: \"element\",\n attributes: { transform: transformStr },\n children: [\n {\n name: \"rect\",\n type: \"element\",\n attributes: {\n class: \"pcb-component\",\n x: (-scaledWidth / 2).toString(),\n y: (-scaledHeight / 2).toString(),\n width: scaledWidth.toString(),\n height: scaledHeight.toString(),\n },\n },\n {\n name: \"rect\",\n type: \"element\",\n attributes: {\n class: \"pcb-component-outline\",\n x: (-scaledWidth / 2).toString(),\n y: (-scaledHeight / 2).toString(),\n width: scaledWidth.toString(),\n height: scaledHeight.toString(),\n },\n },\n ],\n }\n}\n\nfunction createPcbHole(hole: any, transform: any): any {\n const [x, y] = applyToPoint(transform, [hole.x, hole.y])\n const scaledOuterRadius = (hole.outer_diameter / 2) * Math.abs(transform.a)\n const scaledInnerRadius = (hole.hole_diameter / 2) * Math.abs(transform.a)\n return {\n name: \"g\",\n type: \"element\",\n children: [\n {\n name: \"circle\",\n type: \"element\",\n attributes: {\n class: \"pcb-hole-outer\",\n cx: x.toString(),\n cy: y.toString(),\n r: scaledOuterRadius.toString(),\n },\n },\n {\n name: \"circle\",\n type: \"element\",\n attributes: {\n class: \"pcb-hole-inner\",\n cx: x.toString(),\n cy: y.toString(),\n r: scaledInnerRadius.toString(),\n },\n },\n ],\n }\n}\n\nfunction createPcbSMTPad(pad: any, transform: any): any {\n const [x, y] = applyToPoint(transform, [pad.x, pad.y])\n const width = pad.width * Math.abs(transform.a)\n const height = pad.height * Math.abs(transform.d)\n return {\n name: \"rect\",\n type: \"element\",\n attributes: {\n class: \"pcb-pad\",\n x: (x - width / 2).toString(),\n y: (y - height / 2).toString(),\n width: width.toString(),\n height: height.toString(),\n },\n }\n}\n\nfunction createPcbTrace(trace: any, transform: any): any {\n if (!trace.route || !Array.isArray(trace.route) || trace.route.length < 2)\n return null\n\n const cornerRadius = 0.2 // Adjust this value to change the roundness of corners\n const pathCommands: string[] = []\n const transformedPoints = trace.route.map((point: any) =>\n applyToPoint(transform, [point.x, point.y]),\n )\n\n // Start path\n pathCommands.push(`M ${transformedPoints[0][0]} ${transformedPoints[0][1]}`)\n\n for (let i = 1; i < transformedPoints.length - 1; i++) {\n const prev = transformedPoints[i - 1]\n const curr = transformedPoints[i]\n const next = transformedPoints[i + 1]\n\n // Calculate vectors\n const v1 = curr && prev ? [curr[0] - prev[0], curr[1] - prev[1]] : [0, 0]\n const v2 = next && curr ? [next[0] - curr[0], next[1] - curr[1]] : [0, 0]\n\n // Normalize vectors\n const l1 = Math.sqrt((v1[0] as number) * (v1[0] as number) + (v1[1] as number) * (v1[1] as number));\n const l2 = Math.sqrt((v2[0] as number) * (v2[0] as number) + (v2[1] as number) * (v2[1] as number));\n if (l1 !== 0) {\n v1[0]! /= l1;\n v1[1]! /= l1;\n }\n if (l2 !== 0) {\n v2[0]! /= l2;\n v2[1]! /= l2;\n }\n\n // Calculate the corner points\n const radius = Math.min(cornerRadius, Math.min(l1, l2) / 2)\n const p1 = [curr[0] - v1[0]! * radius, curr[1] - v1[1]! * radius] \n const p2 = [curr[0] + v2[0]! * radius, curr[1] + v2[1]! * radius]\n\n // Add line to the start of the corner\n pathCommands.push(`L ${p1[0]} ${p1[1]}`)\n\n // Add the arc\n pathCommands.push(`A ${radius} ${radius} 0 0 1 ${p2[0]} ${p2[1]}`)\n }\n\n // Add final line to last point\n const lastPoint = transformedPoints[transformedPoints.length - 1]\n pathCommands.push(`L ${lastPoint[0]} ${lastPoint[1]}`)\n\n return {\n name: \"path\",\n type: \"element\",\n attributes: {\n class: \"pcb-trace\",\n d: pathCommands.join(\" \"),\n \"stroke-width\": trace.stroke_width\n ? (trace.stroke_width * Math.abs(transform.a)).toString()\n : \"0.3\",\n \"stroke-linecap\": \"round\",\n \"stroke-linejoin\": \"round\",\n },\n }\n}\n\nfunction createPcbSilkscreenPath(silkscreenPath: any, transform: any): any {\n if (!silkscreenPath.route || !Array.isArray(silkscreenPath.route)) return null\n\n let path = silkscreenPath.route\n .map((point: any, index: number) => {\n const [x, y] = applyToPoint(transform, [point.x, point.y])\n return index === 0 ? `M ${x} ${y}` : `L ${x} ${y}`\n })\n .join(\" \")\n\n // Close the path if it's not already closed\n const firstPoint = silkscreenPath.route[0]\n const lastPoint = silkscreenPath.route[silkscreenPath.route.length - 1]\n if (firstPoint.x !== lastPoint.x || firstPoint.y !== lastPoint.y) {\n path += \" Z\"\n }\n\n return {\n name: \"path\",\n type: \"element\",\n attributes: {\n class: `pcb-silkscreen pcb-silkscreen-${silkscreenPath.layer}`,\n d: path,\n \"stroke-width\": (\n silkscreenPath.stroke_width * Math.abs(transform.a)\n ).toString(),\n \"data-pcb-component-id\": silkscreenPath.pcb_component_id,\n \"data-pcb-silkscreen-path-id\": silkscreenPath.pcb_silkscreen_path_id,\n },\n }\n}\n\nfunction createPcbBoundary(\n transform: any,\n minX: number,\n minY: number,\n maxX: number,\n maxY: number,\n): any {\n const [x1, y1] = applyToPoint(transform, [minX, minY])\n const [x2, y2] = applyToPoint(transform, [maxX, maxY])\n const width = Math.abs(x2 - x1)\n const height = Math.abs(y2 - y1)\n const x = Math.min(x1, x2)\n const y = Math.min(y1, y2)\n return {\n name: \"rect\",\n type: \"element\",\n attributes: {\n class: \"pcb-boundary\",\n x: x.toString(),\n y: y.toString(),\n width: width.toString(),\n height: height.toString(),\n },\n }\n}\n\nexport { circuitJsonToPcbSvg }\n","import type { AnySoupElement } from \"@tscircuit/soup\";\nimport { getSvg, symbols } from \"schematic-symbols\";\nimport { parseSync, stringify } from \"svgson\";\n\nfunction circuitJsonToSchematicSvg(soup: AnySoupElement[]): string {\n let minX = Number.POSITIVE_INFINITY;\n let minY = Number.POSITIVE_INFINITY;\n let maxX = Number.NEGATIVE_INFINITY;\n let maxY = Number.NEGATIVE_INFINITY;\n\n const portSize = 0.2;\n const portPositions = new Map();\n\n // First pass: find the bounds and collect port positions\n for (const item of soup) {\n if (item.type === \"schematic_component\") {\n updateBounds(item.center, item.size, item.rotation || 0);\n } else if (item.type === \"schematic_port\") {\n updateBounds(item.center, { width: portSize, height: portSize }, 0);\n portPositions.set(item.schematic_port_id, item.center);\n } else if (item.type === \"schematic_text\") {\n updateBounds(item.position, { width: 0, height: 0 }, 0);\n }\n }\n\n const height = maxY - minY;\n const flipY = (y: number) => height - (y - minY) + minY;\n\n const svgChildren: any[] = [];\n\n // Process components\n const componentMap = new Map();\n for (const component of soup.filter(\n (item) => item.type === \"schematic_component\"\n )) {\n const flippedCenter = {\n x: component.center.x,\n y: flipY(component.center.y),\n };\n const svg = createSchematicComponent(\n flippedCenter,\n component.size,\n component.rotation || 0,\n component.symbol_name\n );\n svgChildren.push(svg);\n componentMap.set(component.schematic_component_id, component);\n }\n\n // Process ports and add lines to component edges\n for (const port of soup.filter((item) => item.type === \"schematic_port\")) {\n const flippedCenter = { x: port.center.x, y: flipY(port.center.y) };\n const svg = createSchematicPort(flippedCenter);\n svgChildren.push(svg);\n\n const component = componentMap.get(port.schematic_component_id);\n if (component) {\n const line = createPortToComponentLine(\n flippedCenter,\n component,\n port.facing_direction || \"right\"\n );\n svgChildren.push(line);\n }\n }\n\n // Process schematic traces\n for (const trace of soup.filter((item) => item.type === \"schematic_trace\")) {\n const svg = createSchematicTrace(trace, flipY, portPositions);\n if (svg) svgChildren.push(svg);\n }\n\n // Process text\n for (const text of soup.filter((item) => item.type === \"schematic_text\")) {\n const flippedPosition = { x: text.position.x, y: flipY(text.position.y) };\n const svg = createSchematicText(text, flippedPosition);\n svgChildren.push(svg);\n }\n\n const padding = 1;\n const width = maxX - minX + 2 * padding;\n const viewBox = `${minX - padding} ${minY - padding} ${width} ${height + 2 * padding}`;\n\n const svgObject = {\n name: \"svg\",\n type: \"element\",\n attributes: {\n xmlns: \"http://www.w3.org/2000/svg\",\n viewBox,\n width: \"1200\",\n height: \"600\",\n style: \"background-color: #fff;\",\n },\n children: [\n {\n name: \"style\",\n type: \"element\",\n children: [\n {\n type: \"text\",\n value: `\n .component { fill: none; stroke: red; stroke-width: 0.03; }\n .component-pin { fill: none; stroke: red; stroke-width: 0.03; }\n .trace { stroke: green; stroke-width: 0.03; fill: none; }\n .text { font-family: Arial, sans-serif; font-size: 0.2px; }\n .port { fill: none; stroke: blue; stroke-width: 0.03; }\n `,\n },\n ],\n },\n ...svgChildren,\n ],\n };\n\n return stringify({ value: \"\", ...svgObject });\n\n function updateBounds(center: any, size: any, rotation: number) {\n const corners = [\n { x: -size.width / 2, y: -size.height / 2 },\n { x: size.width / 2, y: -size.height / 2 },\n { x: size.width / 2, y: size.height / 2 },\n { x: -size.width / 2, y: size.height / 2 },\n ];\n\n for (const corner of corners) {\n const rotatedX =\n corner.x * Math.cos(rotation) -\n corner.y * Math.sin(rotation) +\n center.x;\n const rotatedY =\n corner.x * Math.sin(rotation) +\n corner.y * Math.cos(rotation) +\n center.y;\n minX = Math.min(minX, rotatedX);\n minY = Math.min(minY, rotatedY);\n maxX = Math.max(maxX, rotatedX);\n maxY = Math.max(maxY, rotatedY);\n }\n }\n}\n\nfunction createSchematicComponent(\n center: { x: number; y: number },\n size: { width: number; height: number },\n rotation: number,\n symbolName?: string\n): any {\n const transform = `translate(${center.x}, ${center.y}) rotate(${(rotation * 180) / Math.PI})`;\n\n if (symbolName) {\n const symbol = (symbols as any)[symbolName];\n const paths = symbol.primitives.filter((p: any) => p.type === \"path\");\n const updatedSymbol = {\n ...symbol,\n primitives: paths,\n };\n const svg = parseSync(\n getSvg(updatedSymbol, {\n width: size.width,\n height: size.height,\n })\n );\n\n // Filter out non-path elements and modify path colors\n const pathElements = svg.children\n .filter(\n (child: any) =>\n child.name === \"path\" && child.attributes.fill !== \"green\"\n )\n .map((path: any) => {\n const currentStrokeWidth = Number.parseFloat(\n path.attributes[\"stroke-width\"] || \"0.02\"\n );\n const newStrokeWidth = (currentStrokeWidth * 1.5).toString();\n\n return {\n ...path,\n attributes: {\n ...path.attributes,\n stroke:\n path.attributes.stroke === \"black\"\n ? \"red\"\n : path.attributes.stroke,\n \"stroke-width\": newStrokeWidth,\n },\n };\n });\n\n // Check if viewBox attribute exists\n const viewBoxAttr = svg.attributes.viewBox;\n if (typeof viewBoxAttr === \"undefined\") {\n throw new Error(\"SVG does not have a viewBox attribute.\");\n }\n\n // Extract viewBox values\n const viewBox = viewBoxAttr.split(\" \").map(Number);\n if (viewBox.length < 4) {\n throw new Error(\"Invalid viewBox attribute.\");\n }\n const [minX, minY, width = 0, height = 0] = viewBox;\n\n // Calculate scale factors\n const scaleX = size.width / (width || 1);\n const scaleY = size.height / (height || 1);\n\n const scale = Math.min(scaleX, scaleY);\n\n // Adjust transformation to include scaling and centering\n const adjustedTransform = `${transform} scale(${scale}) translate(${-(minX ?? 0) - width / 2}, ${-(minY ?? 0) - height / 2})`;\n\n return {\n name: \"g\",\n type: \"element\",\n attributes: { transform: adjustedTransform },\n children: pathElements,\n };\n }\n\n return {\n name: \"g\",\n type: \"element\",\n attributes: { transform },\n children: [\n {\n name: \"rect\",\n type: \"element\",\n attributes: {\n class: \"component\",\n x: (-size.width / 2).toString(),\n y: (-size.height / 2).toString(),\n width: size.width.toString(),\n height: size.height.toString(),\n },\n },\n ],\n };\n}\n\nfunction createSchematicPort(center: { x: number; y: number }): any {\n const portSize = 0.2;\n const x = center.x - portSize / 2;\n const y = center.y - portSize / 2;\n\n return {\n name: \"rect\",\n type: \"element\",\n attributes: {\n class: \"port\",\n x: x.toString(),\n y: y.toString(),\n width: portSize.toString(),\n height: portSize.toString(),\n },\n };\n}\n\nfunction createPortToComponentLine(\n portCenter: { x: number; y: number },\n component: any,\n facingDirection: string\n): any {\n const componentCenter = { x: component.center.x, y: portCenter.y };\n const halfWidth = component.size.width / 2;\n const halfHeight = component.size.height / 2;\n\n let endX = portCenter.x;\n let endY = portCenter.y;\n\n switch (facingDirection) {\n case \"left\":\n endX = componentCenter.x - halfWidth;\n break;\n case \"right\":\n endX = componentCenter.x + halfWidth;\n break;\n case \"up\":\n endY = componentCenter.y - halfHeight;\n break;\n case \"down\":\n endY = componentCenter.y + halfHeight;\n break;\n }\n\n return {\n name: \"line\",\n type: \"element\",\n attributes: {\n class: \"component-pin\",\n x1: portCenter.x.toString(),\n y1: portCenter.y.toString(),\n x2: endX.toString(),\n y2: endY.toString(),\n },\n };\n}\n\nfunction createSchematicTrace(\n trace: any,\n flipY: (y: number) => number,\n portPositions: Map<string, { x: number; y: number }>\n): any {\n const edges = trace.edges;\n if (edges.length === 0) return null;\n\n let path = \"\";\n\n // Process all edges\n edges.forEach((edge: any, index: number) => {\n const fromPoint =\n edge.from.ti !== undefined ? portPositions.get(edge.from.ti) : edge.from;\n const toPoint =\n edge.to.ti !== undefined ? portPositions.get(edge.to.ti) : edge.to;\n\n if (!fromPoint || !toPoint) {\n return;\n }\n\n const fromCoord = `${fromPoint.x} ${flipY(fromPoint.y)}`;\n const toCoord = `${toPoint.x} ${flipY(toPoint.y)}`;\n\n if (index === 0) {\n path += `M ${fromCoord} L ${toCoord}`;\n } else {\n path += ` L ${toCoord}`;\n }\n });\n\n // Handle connection to final port if needed\n if (trace.to_schematic_port_id) {\n const finalPort = portPositions.get(trace.to_schematic_port_id);\n if (finalPort) {\n const lastFromPoint = path.split(\"M\")[1]?.split(\"L\")[0];\n const lastEdge = edges[edges.length - 1];\n const lastPoint =\n lastEdge.to.ti !== undefined\n ? portPositions.get(lastEdge.to.ti)\n : lastEdge.to;\n if (lastPoint.x !== finalPort.x || lastPoint.y !== finalPort.y) {\n const finalCoord = `${finalPort.x} ${flipY(finalPort.y)}`;\n path += ` M ${lastFromPoint} L ${finalCoord}`;\n }\n }\n }\n\n return path\n ? {\n name: \"path\",\n type: \"element\",\n attributes: {\n class: \"trace\",\n d: path,\n },\n }\n : null;\n}\n\nfunction createSchematicText(\n text: any,\n position: { x: number; y: number }\n): any {\n return {\n name: \"text\",\n type: \"element\",\n attributes: {\n class: \"text\",\n x: position.x.toString(),\n y: position.y.toString(),\n \"text-anchor\": getTextAnchor(text.anchor),\n \"dominant-baseline\": \"middle\",\n },\n children: [\n {\n type: \"text\",\n value: text.text ? text.text : \"\",\n },\n ],\n };\n}\n\nfunction getTextAnchor(anchor: string): string {\n switch (anchor) {\n case \"left\":\n return \"start\";\n case \"right\":\n return \"end\";\n default:\n return \"middle\";\n }\n}\n\nexport { circuitJsonToSchematicSvg };\n"],"mappings":"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","names":["import_svgson","scale"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/lib/circuit-to-pcb-svg.ts","../src/lib/circuit-to-schematic-svg.ts"],"sourcesContent":["export * from \"./lib\";\n\n","import type { AnySoupElement } from \"@tscircuit/soup\"\nimport { type INode, stringify } from \"svgson\"\nimport { applyToPoint, compose, scale, translate } from \"transformation-matrix\"\n\ninterface SvgObject {\n name: string\n type: \"element\" | \"text\"\n attributes?: { [key: string]: string }\n children?: SvgObject[]\n value?: string\n}\n\ninterface PointObjectNotation {\n x: number\n y: number\n}\n\nfunction circuitJsonToPcbSvg(soup: AnySoupElement[]): string {\n let minX = Number.POSITIVE_INFINITY\n let minY = Number.POSITIVE_INFINITY\n let maxX = Number.NEGATIVE_INFINITY\n let maxY = Number.NEGATIVE_INFINITY\n\n // Process all elements to determine bounds\n for (const item of soup) {\n if (\"center\" in item && \"width\" in item && \"height\" in item) {\n updateBounds(item.center, item.width, item.height)\n } else if (\"x\" in item && \"y\" in item) {\n updateBounds({ x: item.x, y: item.y }, 0, 0)\n } else if (\"route\" in item) {\n updateTraceBounds(item.route)\n }\n }\n\n const padding = 1 // Reduced padding for tighter boundary\n const circuitWidth = maxX - minX + 2 * padding\n const circuitHeight = maxY - minY + 2 * padding\n\n const svgWidth = 800\n const svgHeight = 600\n const paths: PointObjectNotation[][] = []\n for (const item of soup) {\n if (\"route\" in item && item.route !== undefined) {\n paths.push(item.route as PointObjectNotation[])\n }\n }\n\n // Calculate scale factor to fit the circuit within the SVG, maintaining aspect ratio\n const scaleX = svgWidth / circuitWidth\n const scaleY = svgHeight / circuitHeight\n const scaleFactor = Math.min(scaleX, scaleY)\n\n // Calculate centering offsets\n const offsetX = (svgWidth - circuitWidth * scaleFactor) / 2\n const offsetY = (svgHeight - circuitHeight * scaleFactor) / 2\n\n const transform = compose(\n translate(\n offsetX - minX * scaleFactor + padding * scaleFactor,\n svgHeight - offsetY + minY * scaleFactor - padding * scaleFactor,\n ),\n scale(scaleFactor, -scaleFactor), // Flip in y-direction\n )\n\n const traceElements = soup\n .filter((item) => item.type === \"pcb_trace\")\n .map((item) => createSvgElement(item, transform))\n .filter((element) => element !== null)\n\n const holeElements = soup\n .filter((item) => item.type === \"pcb_plated_hole\")\n .map((item) => createSvgElement(item, transform))\n .filter((element) => element !== null)\n\n const silkscreenElements = soup\n .filter((item) => item.type === \"pcb_silkscreen_path\")\n .map((item) => createPcbSilkscreenPath(item, transform))\n .filter((element) => element !== null)\n\n const otherElements = soup\n .filter(\n (item) =>\n ![\"pcb_trace\", \"pcb_plated_hole\", \"pcb_silkscreen_path\"].includes(\n item.type,\n ),\n )\n .map((item) => createSvgElement(item, transform))\n .filter((element) => element !== null)\n\n let strokeWidth = String(0.05 * scaleFactor)\n\n for (const element of soup) {\n if (\"stroke_width\" in element) {\n strokeWidth = String(scaleFactor * element.stroke_width)\n break\n }\n }\n\n const svgObject: SvgObject = {\n name: \"svg\",\n type: \"element\",\n attributes: {\n xmlns: \"http://www.w3.org/2000/svg\",\n width: svgWidth.toString(),\n height: svgHeight.toString(),\n },\n children: [\n {\n name: \"style\",\n type: \"element\",\n children: [\n {\n type: \"text\",\n value: `\n .pcb-board { fill: #000; }\n .pcb-trace { stroke: rgb(200, 52, 52); stroke-width: ${strokeWidth}; fill: none; }\n .pcb-hole-outer { fill: rgb(200, 52, 52); }\n .pcb-hole-inner { fill: rgb(255, 38, 226); }\n .pcb-pad { fill: rgb(200, 52, 52); }\n .pcb-boundary { fill: none; stroke: #fff; stroke-width: 0.3; }\n .pcb-silkscreen { fill: none; }\n .pcb-silkscreen-top { stroke: #f2eda1; }\n .pcb-silkscreen-bottom { stroke: #f2eda1; }\n `,\n },\n ],\n },\n {\n name: \"rect\",\n type: \"element\",\n attributes: {\n class: \"pcb-board\",\n x: \"0\",\n y: \"0\",\n width: svgWidth.toString(),\n height: svgHeight.toString(),\n },\n },\n createPcbBoundary(transform, minX, minY, maxX, maxY),\n {\n name: \"g\",\n type: \"element\",\n attributes: { id: \"other-elements\" },\n children: otherElements,\n },\n {\n name: \"g\",\n type: \"element\",\n attributes: { id: \"traces\" },\n children: traceElements,\n },\n {\n name: \"g\",\n type: \"element\",\n attributes: { id: \"holes\" },\n children: holeElements,\n },\n {\n name: \"g\",\n type: \"element\",\n attributes: { id: \"silkscreen\" },\n children: silkscreenElements,\n },\n ].filter((child) => child !== null),\n }\n\n try {\n return stringify(svgObject as INode)\n } catch (error) {\n console.error(\"Error stringifying SVG object:\", error)\n throw error\n }\n\n function updateBounds(center: any, width: any, height: any) {\n const halfWidth = width / 2\n const halfHeight = height / 2\n minX = Math.min(minX, center.x - halfWidth)\n minY = Math.min(minY, center.y - halfHeight)\n maxX = Math.max(maxX, center.x + halfWidth)\n maxY = Math.max(maxY, center.y + halfHeight)\n }\n\n function updateTraceBounds(route: any[]) {\n for (const point of route) {\n minX = Math.min(minX, point.x)\n minY = Math.min(minY, point.y)\n maxX = Math.max(maxX, point.x)\n maxY = Math.max(maxY, point.y)\n }\n }\n}\n\nfunction createSvgElement(item: AnySoupElement, transform: any): any {\n switch (item.type) {\n case \"pcb_component\":\n return createPcbComponent(item, transform)\n case \"pcb_trace\":\n return createPcbTrace(item, transform)\n case \"pcb_plated_hole\":\n return createPcbHole(item, transform)\n case \"pcb_smtpad\":\n return createPcbSMTPad(item, transform)\n default:\n return null\n }\n}\n\nfunction createPcbComponent(component: any, transform: any): any {\n const { center, width, height, rotation = 0 } = component\n const [x, y] = applyToPoint(transform, [center.x, center.y])\n const scaledWidth = width * Math.abs(transform.a)\n const scaledHeight = height * Math.abs(transform.d)\n const transformStr = `translate(${x}, ${y}) rotate(${-rotation}) scale(1, -1)`\n\n return {\n name: \"g\",\n type: \"element\",\n attributes: { transform: transformStr },\n children: [\n {\n name: \"rect\",\n type: \"element\",\n attributes: {\n class: \"pcb-component\",\n x: (-scaledWidth / 2).toString(),\n y: (-scaledHeight / 2).toString(),\n width: scaledWidth.toString(),\n height: scaledHeight.toString(),\n },\n },\n {\n name: \"rect\",\n type: \"element\",\n attributes: {\n class: \"pcb-component-outline\",\n x: (-scaledWidth / 2).toString(),\n y: (-scaledHeight / 2).toString(),\n width: scaledWidth.toString(),\n height: scaledHeight.toString(),\n },\n },\n ],\n }\n}\n\nfunction createPcbHole(hole: any, transform: any): any {\n const [x, y] = applyToPoint(transform, [hole.x, hole.y])\n const scaledOuterRadius = (hole.outer_diameter / 2) * Math.abs(transform.a)\n const scaledInnerRadius = (hole.hole_diameter / 2) * Math.abs(transform.a)\n return {\n name: \"g\",\n type: \"element\",\n children: [\n {\n name: \"circle\",\n type: \"element\",\n attributes: {\n class: \"pcb-hole-outer\",\n cx: x.toString(),\n cy: y.toString(),\n r: scaledOuterRadius.toString(),\n },\n },\n {\n name: \"circle\",\n type: \"element\",\n attributes: {\n class: \"pcb-hole-inner\",\n cx: x.toString(),\n cy: y.toString(),\n r: scaledInnerRadius.toString(),\n },\n },\n ],\n }\n}\n\nfunction createPcbSMTPad(pad: any, transform: any): any {\n const [x, y] = applyToPoint(transform, [pad.x, pad.y])\n const width = pad.width * Math.abs(transform.a)\n const height = pad.height * Math.abs(transform.d)\n return {\n name: \"rect\",\n type: \"element\",\n attributes: {\n class: \"pcb-pad\",\n x: (x - width / 2).toString(),\n y: (y - height / 2).toString(),\n width: width.toString(),\n height: height.toString(),\n },\n }\n}\n\nfunction createPcbTrace(trace: any, transform: any): any {\n if (!trace.route || !Array.isArray(trace.route) || trace.route.length < 2)\n return null\n\n const cornerRadius = 0.2 // Adjust this value to change the roundness of corners\n const pathCommands: string[] = []\n const transformedPoints = trace.route.map((point: any) =>\n applyToPoint(transform, [point.x, point.y]),\n )\n\n // Start path\n pathCommands.push(`M ${transformedPoints[0][0]} ${transformedPoints[0][1]}`)\n\n for (let i = 1; i < transformedPoints.length - 1; i++) {\n const prev = transformedPoints[i - 1]\n const curr = transformedPoints[i]\n const next = transformedPoints[i + 1]\n\n // Calculate vectors\n const v1 = curr && prev ? [curr[0] - prev[0], curr[1] - prev[1]] : [0, 0]\n const v2 = next && curr ? [next[0] - curr[0], next[1] - curr[1]] : [0, 0]\n\n // Normalize vectors\n const l1 = Math.sqrt((v1[0] as number) * (v1[0] as number) + (v1[1] as number) * (v1[1] as number));\n const l2 = Math.sqrt((v2[0] as number) * (v2[0] as number) + (v2[1] as number) * (v2[1] as number));\n if (l1 !== 0) {\n v1[0]! /= l1;\n v1[1]! /= l1;\n }\n if (l2 !== 0) {\n v2[0]! /= l2;\n v2[1]! /= l2;\n }\n\n // Calculate the corner points\n const radius = Math.min(cornerRadius, Math.min(l1, l2) / 2)\n const p1 = [curr[0] - v1[0]! * radius, curr[1] - v1[1]! * radius] \n const p2 = [curr[0] + v2[0]! * radius, curr[1] + v2[1]! * radius]\n\n // Add line to the start of the corner\n pathCommands.push(`L ${p1[0]} ${p1[1]}`)\n\n // Add the arc\n pathCommands.push(`A ${radius} ${radius} 0 0 1 ${p2[0]} ${p2[1]}`)\n }\n\n // Add final line to last point\n const lastPoint = transformedPoints[transformedPoints.length - 1]\n pathCommands.push(`L ${lastPoint[0]} ${lastPoint[1]}`)\n\n return {\n name: \"path\",\n type: \"element\",\n attributes: {\n class: \"pcb-trace\",\n d: pathCommands.join(\" \"),\n \"stroke-width\": trace.stroke_width\n ? (trace.stroke_width * Math.abs(transform.a)).toString()\n : \"0.3\",\n \"stroke-linecap\": \"round\",\n \"stroke-linejoin\": \"round\",\n },\n }\n}\n\nfunction createPcbSilkscreenPath(silkscreenPath: any, transform: any): any {\n if (!silkscreenPath.route || !Array.isArray(silkscreenPath.route)) return null\n\n let path = silkscreenPath.route\n .map((point: any, index: number) => {\n const [x, y] = applyToPoint(transform, [point.x, point.y])\n return index === 0 ? `M ${x} ${y}` : `L ${x} ${y}`\n })\n .join(\" \")\n\n // Close the path if it's not already closed\n const firstPoint = silkscreenPath.route[0]\n const lastPoint = silkscreenPath.route[silkscreenPath.route.length - 1]\n if (firstPoint.x !== lastPoint.x || firstPoint.y !== lastPoint.y) {\n path += \" Z\"\n }\n\n return {\n name: \"path\",\n type: \"element\",\n attributes: {\n class: `pcb-silkscreen pcb-silkscreen-${silkscreenPath.layer}`,\n d: path,\n \"stroke-width\": (\n silkscreenPath.stroke_width * Math.abs(transform.a)\n ).toString(),\n \"data-pcb-component-id\": silkscreenPath.pcb_component_id,\n \"data-pcb-silkscreen-path-id\": silkscreenPath.pcb_silkscreen_path_id,\n },\n }\n}\n\nfunction createPcbBoundary(\n transform: any,\n minX: number,\n minY: number,\n maxX: number,\n maxY: number,\n): any {\n const [x1, y1] = applyToPoint(transform, [minX, minY])\n const [x2, y2] = applyToPoint(transform, [maxX, maxY])\n const width = Math.abs(x2 - x1)\n const height = Math.abs(y2 - y1)\n const x = Math.min(x1, x2)\n const y = Math.min(y1, y2)\n return {\n name: \"rect\",\n type: \"element\",\n attributes: {\n class: \"pcb-boundary\",\n x: x.toString(),\n y: y.toString(),\n width: width.toString(),\n height: height.toString(),\n },\n }\n}\n\nexport { circuitJsonToPcbSvg }\n","import type { AnySoupElement } from \"@tscircuit/soup\";\nimport { getSvg, symbols } from \"schematic-symbols\";\nimport { parseSync, stringify } from \"svgson\";\n\nfunction circuitJsonToSchematicSvg(soup: AnySoupElement[]): string {\n let minX = Number.POSITIVE_INFINITY;\n let minY = Number.POSITIVE_INFINITY;\n let maxX = Number.NEGATIVE_INFINITY;\n let maxY = Number.NEGATIVE_INFINITY;\n\n const portSize = 0.2;\n const portPositions = new Map();\n\n // First pass: find the bounds and collect port positions\n for (const item of soup) {\n if (item.type === \"schematic_component\") {\n updateBounds(item.center, item.size, item.rotation || 0);\n } else if (item.type === \"schematic_port\") {\n updateBounds(item.center, { width: portSize, height: portSize }, 0);\n portPositions.set(item.schematic_port_id, item.center);\n } else if (item.type === \"schematic_text\") {\n updateBounds(item.position, { width: 0, height: 0 }, 0);\n }\n }\n\n const height = maxY - minY;\n const flipY = (y: number) => height - (y - minY) + minY;\n\n const svgChildren: any[] = [];\n\n // Process components\n const componentMap = new Map();\n for (const component of soup.filter(\n (item) => item.type === \"schematic_component\"\n )) {\n const flippedCenter = {\n x: component.center.x,\n y: flipY(component.center.y),\n };\n const svg = createSchematicComponent(\n flippedCenter,\n component.size,\n component.rotation || 0,\n component.symbol_name\n );\n svgChildren.push(svg);\n componentMap.set(component.schematic_component_id, component);\n }\n\n // Process ports and add lines to component edges\n for (const port of soup.filter((item) => item.type === \"schematic_port\")) {\n const flippedCenter = { x: port.center.x, y: flipY(port.center.y) };\n const svg = createSchematicPort(flippedCenter);\n svgChildren.push(svg);\n\n const component = componentMap.get(port.schematic_component_id);\n if (component) {\n const line = createPortToComponentLine(\n flippedCenter,\n component,\n port.facing_direction || \"right\"\n );\n svgChildren.push(line);\n }\n }\n\n // Process schematic traces\n for (const trace of soup.filter((item) => item.type === \"schematic_trace\")) {\n const svg = createSchematicTrace(trace, flipY, portPositions);\n if (svg) svgChildren.push(svg);\n }\n\n // Process text\n for (const text of soup.filter((item) => item.type === \"schematic_text\")) {\n const flippedPosition = { x: text.position.x, y: flipY(text.position.y) };\n const svg = createSchematicText(text, flippedPosition);\n svgChildren.push(svg);\n }\n\n const padding = 1;\n const width = maxX - minX + 2 * padding;\n const viewBox = `${minX - padding} ${minY - padding} ${width} ${height + 2 * padding}`;\n\n const svgObject = {\n name: \"svg\",\n type: \"element\",\n attributes: {\n xmlns: \"http://www.w3.org/2000/svg\",\n viewBox,\n width: \"1200\",\n height: \"600\",\n style: \"background-color: #fff;\",\n },\n children: [\n {\n name: \"style\",\n type: \"element\",\n children: [\n {\n type: \"text\",\n value: `\n .component { fill: none; stroke: red; stroke-width: 0.03; }\n .component-pin { fill: none; stroke: red; stroke-width: 0.03; }\n .trace { stroke: green; stroke-width: 0.03; fill: none; }\n .text { font-family: Arial, sans-serif; font-size: 0.2px; }\n .port { fill: none; stroke: blue; stroke-width: 0.03; }\n `,\n },\n ],\n },\n ...svgChildren,\n ],\n };\n\n return stringify({ value: \"\", ...svgObject });\n\n function updateBounds(center: any, size: any, rotation: number) {\n const corners = [\n { x: -size.width / 2, y: -size.height / 2 },\n { x: size.width / 2, y: -size.height / 2 },\n { x: size.width / 2, y: size.height / 2 },\n { x: -size.width / 2, y: size.height / 2 },\n ];\n\n for (const corner of corners) {\n const rotatedX =\n corner.x * Math.cos(rotation) -\n corner.y * Math.sin(rotation) +\n center.x;\n const rotatedY =\n corner.x * Math.sin(rotation) +\n corner.y * Math.cos(rotation) +\n center.y;\n minX = Math.min(minX, rotatedX);\n minY = Math.min(minY, rotatedY);\n maxX = Math.max(maxX, rotatedX);\n maxY = Math.max(maxY, rotatedY);\n }\n }\n}\n\nfunction createSchematicComponent(\n center: { x: number; y: number },\n size: { width: number; height: number },\n rotation: number,\n symbolName?: string\n): any {\n const transform = `translate(${center.x}, ${center.y}) rotate(${(rotation * 180) / Math.PI})`;\n\n if (symbolName) {\n const symbol = (symbols as any)[symbolName];\n const paths = symbol.primitives.filter((p: any) => p.type === \"path\");\n const updatedSymbol = {\n ...symbol,\n primitives: paths,\n };\n const svg = parseSync(\n getSvg(updatedSymbol, {\n width: size.width,\n height: size.height,\n })\n );\n\n // Filter out non-path elements and modify path colors\n const pathElements = svg.children\n .filter(\n (child: any) =>\n child.name === \"path\" && child.attributes.fill !== \"green\"\n )\n .map((path: any) => {\n const currentStrokeWidth = Number.parseFloat(\n path.attributes[\"stroke-width\"] || \"0.02\"\n );\n const newStrokeWidth = (currentStrokeWidth * 1.5).toString();\n\n return {\n ...path,\n attributes: {\n ...path.attributes,\n stroke:\n path.attributes.stroke === \"black\"\n ? \"red\"\n : path.attributes.stroke,\n \"stroke-width\": newStrokeWidth,\n },\n };\n });\n\n // Check if viewBox attribute exists\n const viewBoxAttr = svg.attributes.viewBox;\n if (typeof viewBoxAttr === \"undefined\") {\n throw new Error(\"SVG does not have a viewBox attribute.\");\n }\n\n // Extract viewBox values\n const viewBox = viewBoxAttr.split(\" \").map(Number);\n if (viewBox.length < 4) {\n throw new Error(\"Invalid viewBox attribute.\");\n }\n const [minX, minY, width = 0, height = 0] = viewBox;\n\n // Calculate scale factors\n const scaleX = size.width / (width || 1);\n const scaleY = size.height / (height || 1);\n\n const scale = Math.min(scaleX, scaleY);\n\n // Adjust transformation to include scaling and centering\n const adjustedTransform = `${transform} scale(${scale}) translate(${-(minX ?? 0) - width / 2}, ${-(minY ?? 0) - height / 2})`;\n\n return {\n name: \"g\",\n type: \"element\",\n attributes: { transform: adjustedTransform },\n children: pathElements,\n };\n }\n\n return {\n name: \"g\",\n type: \"element\",\n attributes: { transform },\n children: [\n {\n name: \"rect\",\n type: \"element\",\n attributes: {\n class: \"component\",\n x: (-size.width / 2).toString(),\n y: (-size.height / 2).toString(),\n width: size.width.toString(),\n height: size.height.toString(),\n },\n },\n ],\n };\n}\n\nfunction createSchematicPort(center: { x: number; y: number }): any {\n const portSize = 0.2;\n const x = center.x - portSize / 2;\n const y = center.y - portSize / 2;\n\n return {\n name: \"rect\",\n type: \"element\",\n attributes: {\n class: \"port\",\n x: x.toString(),\n y: y.toString(),\n width: portSize.toString(),\n height: portSize.toString(),\n },\n };\n}\n\nfunction createPortToComponentLine(\n portCenter: { x: number; y: number },\n component: any,\n facingDirection: string\n): any {\n const componentCenter = { x: component.center.x, y: portCenter.y };\n const halfWidth = component.size.width / 2;\n const halfHeight = component.size.height / 2;\n\n let endX = portCenter.x;\n let endY = portCenter.y;\n\n switch (facingDirection) {\n case \"left\":\n endX = componentCenter.x - halfWidth;\n break;\n case \"right\":\n endX = componentCenter.x + halfWidth;\n break;\n case \"up\":\n endY = componentCenter.y - halfHeight;\n break;\n case \"down\":\n endY = componentCenter.y + halfHeight;\n break;\n }\n\n return {\n name: \"line\",\n type: \"element\",\n attributes: {\n class: \"component-pin\",\n x1: portCenter.x.toString(),\n y1: portCenter.y.toString(),\n x2: endX.toString(),\n y2: endY.toString(),\n },\n };\n}\n\nfunction createSchematicTrace(\n trace: any,\n flipY: (y: number) => number,\n portPositions: Map<string, { x: number; y: number }>\n): any {\n const edges = trace.edges;\n if (edges.length === 0) return null;\n\n let path = \"\";\n\n // Process all edges\n edges.forEach((edge: any, index: number) => {\n const fromPoint =\n edge.from.ti !== undefined ? portPositions.get(edge.from.ti) : edge.from;\n const toPoint =\n edge.to.ti !== undefined ? portPositions.get(edge.to.ti) : edge.to;\n\n if (!fromPoint || !toPoint) {\n return;\n }\n\n const fromCoord = `${fromPoint.x} ${flipY(fromPoint.y)}`;\n const toCoord = `${toPoint.x} ${flipY(toPoint.y)}`;\n\n if (index === 0) {\n path += `M ${fromCoord} L ${toCoord}`;\n } else {\n path += ` L ${toCoord}`;\n }\n });\n\n // Handle connection to final port if needed\n if (trace.to_schematic_port_id) {\n const finalPort = portPositions.get(trace.to_schematic_port_id);\n if (finalPort) {\n const lastFromPoint = path.split(\"M\")[1]?.split(\"L\")[0];\n const lastEdge = edges[edges.length - 1];\n const lastPoint =\n lastEdge.to.ti !== undefined\n ? portPositions.get(lastEdge.to.ti)\n : lastEdge.to;\n if (lastPoint.x !== finalPort.x || lastPoint.y !== finalPort.y) {\n const finalCoord = `${finalPort.x} ${flipY(finalPort.y)}`;\n path += ` M ${lastFromPoint} L ${finalCoord}`;\n }\n }\n }\n\n return path\n ? {\n name: \"path\",\n type: \"element\",\n attributes: {\n class: \"trace\",\n d: path,\n },\n }\n : null;\n}\n\nfunction createSchematicText(\n text: any,\n position: { x: number; y: number }\n): any {\n return {\n name: \"text\",\n type: \"element\",\n attributes: {\n class: \"text\",\n x: position.x.toString(),\n y: position.y.toString(),\n \"text-anchor\": getTextAnchor(text.anchor),\n \"dominant-baseline\": \"middle\",\n },\n children: [\n {\n type: \"text\",\n value: text.text ? text.text : \"\",\n },\n ],\n };\n}\n\nfunction getTextAnchor(anchor: string): string {\n switch (anchor) {\n case \"left\":\n return \"start\";\n case \"right\":\n return \"end\";\n default:\n return \"middle\";\n }\n}\n\nexport { circuitJsonToSchematicSvg };\n"],"mappings":"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","names":["import_svgson","scale"]}
|