diff --git a/src/Schematic.tsx b/src/Schematic.tsx index d6024dc..207baa8 100644 --- a/src/Schematic.tsx +++ b/src/Schematic.tsx @@ -2,17 +2,18 @@ import { useRenderedCircuit } from "@tscircuit/core" import { findBoundsAndCenter } from "@tscircuit/soup-util" import type { AnyCircuitElement } from "circuit-json" import { useGlobalStore } from "lib/render-context" -import React, { useCallback, useEffect, useRef, useState } from "react" +import type React from "react" +import { useCallback, useEffect, useRef, useState } from "react" import { ErrorBoundary as TypedErrorBoundary } from "react-error-boundary" import { SuperGrid, toMMSI } from "react-supergrid" import useMeasure from "react-use-measure" import { ContextProviders } from "schematic-components" import { SchematicElement } from "schematic-components/SchematicElement" import { + type Matrix, applyToPoint, compose, inverse, - Matrix, scale, translate, } from "transformation-matrix" @@ -122,7 +123,7 @@ export const SchematicWithoutContext = ({ updateTransform(newTransform) } - }, [elements, bounds.width, bounds.height, updateTransform]) + }, [elements, updateTransform]) const handleMouseDown = useCallback((e: React.MouseEvent) => { isDraggingRef.current = true @@ -156,7 +157,7 @@ export const SchematicWithoutContext = ({ const handleWheel = useCallback( (e: WheelEvent) => { e.preventDefault() - const scaleMultiplier = Math.pow(0.999, e.deltaY) + const scaleMultiplier = 0.999 ** e.deltaY if (containerRef.current) { const rect = containerRef.current.getBoundingClientRect() @@ -228,7 +229,7 @@ export const SchematicWithoutContext = ({ transform={transformRef.current} /> {elements?.map((elm, i) => ( - + { const ct = useGlobalStore((s) => s.camera_transform) const pathBounds = getSVGPathBounds( - paths.filter((p): p is PathProps => p.type !== "circle").map((p) => p.d), + paths + .filter((p): p is PathProps => p.type !== "circle" && p.type !== "text") + .map((p) => p.d), ) - const padding = { x: 0, y: 0 } const absoluteCenter = applyToPoint(ct, center) const innerSize = { @@ -65,17 +78,13 @@ export const SVGPathComponent = ({ width: innerSize.width + padding.x * 2, height: innerSize.height + padding.y * 2, } - const [hovering, setHovering] = useState(false) - const svgLeft = absoluteCenter.x - fullSize.width / 2 const svgTop = absoluteCenter.y - fullSize.height / 2 - const preferredRatio = pathBounds.width === 0 ? innerSize.height / pathBounds.height : innerSize.width / pathBounds.width - const svgToScreen = compose( scale( pathBounds.width === 0 @@ -88,10 +97,15 @@ export const SVGPathComponent = ({ translate(-pathBounds.minX, -pathBounds.minY), ) + const baseFontSize = 0.15 // Fixed base font size in schematic units + return ( + // biome-ignore lint/a11y/noSvgWithoutTitle: setHovering(Boolean(hoverContent))} + onFocus={() => setHovering(Boolean(hoverContent))} onMouseOut={() => setHovering(false)} + onBlur={() => setHovering(false)} style={{ position: "absolute", cursor: hovering ? "pointer" : undefined, @@ -108,26 +122,51 @@ export const SVGPathComponent = ({ width={fullSize.width} height={fullSize.height} > - {paths.map((p, i) => - p.type === "circle" ? ( - - ) : ( + {paths.map((p, i) => { + if (p.type === "circle") { + return ( + + ) + } + if (p.type === "text") { + const transformedPos = applyToPoint(svgToScreen, { x: p.cx, y: p.cy }) + const scaleFactor = fullSize.width / pathBounds.width || 1 + + return ( + + + {p.text} + + + ) + } + // Handle the "path" type directly + return ( - ), - )} + ) + })} ) } diff --git a/src/schematic-components/SchematicChip.tsx b/src/schematic-components/SchematicChip.tsx index 137feb7..39cdece 100644 --- a/src/schematic-components/SchematicChip.tsx +++ b/src/schematic-components/SchematicChip.tsx @@ -1,11 +1,11 @@ -import { +import type { AnyCircuitElement, SchematicPort as OriginalSchematicPort, SchematicComponent, } from "circuit-json" -import * as Type from "lib/types" +import type * as Type from "lib/types" import { colorMap } from "lib/utils/colors" -import React from "react" +import type React from "react" import SVGPathComponent from "./SVGPathComponent" import SchematicText from "./SchematicText" @@ -37,7 +37,7 @@ export const SchematicChip: React.FC = ({ const chipHeight = size.height const paths: Array<{ - type?: "path" | "circle" + type: "path" | "circle" | "text" strokeWidth: number stroke: string fill?: string @@ -45,6 +45,9 @@ export const SchematicChip: React.FC = ({ cx?: number cy?: number r?: number + text?: string + anchor?: string + rotation?: number }> = [] // Main chip rectangle @@ -62,31 +65,23 @@ export const SchematicChip: React.FC = ({ item.schematic_component_id === schematic_component_id, ) - const portLength = 0.2 - const circleRadius = 0.05 + const portLength = 0.5 + const circleRadius = 0.04 const labelOffset = 0.1 - const pinLabels: Array<{ - x: number - y: number - text: string - anchor: string - rotation: number - }> = [] - - schematicPorts.forEach((port) => { + for (const port of schematicPorts) { const { side, pinNumber, distanceFromEdge } = port.center - let x = 0, - y = 0, - endX = 0, - endY = 0 - let labelX = 0, - labelY = 0 + let x = 0 + let y = 0 + let endX = 0 + let endY = 0 + let pinX = 0 + let pinY = 0 let textAnchor = "middle" let rotation = 0 if (side === "center") { - return + continue } switch (side) { @@ -95,17 +90,17 @@ export const SchematicChip: React.FC = ({ y = -chipHeight / 2 + distanceFromEdge endX = x - portLength endY = y - labelX = endX - labelY = y + labelOffset - textAnchor = "end" + pinX = x - portLength / 2 + pinY = y + labelOffset + textAnchor = "middle" break case "right": x = chipWidth / 2 y = chipHeight / 2 - distanceFromEdge endX = x + portLength endY = y - labelX = endX - labelOffset - labelY = y + labelOffset + pinX = x + portLength / 2 - labelOffset + pinY = y + labelOffset textAnchor = "start" break case "bottom": @@ -113,8 +108,8 @@ export const SchematicChip: React.FC = ({ y = -chipHeight / 2 endX = x endY = y - portLength - labelX = x - labelY = endY + labelOffset + pinX = x - labelOffset + pinY = y - portLength / 2 rotation = -90 break case "top": @@ -122,8 +117,8 @@ export const SchematicChip: React.FC = ({ y = chipHeight / 2 endX = x endY = y + portLength - labelX = x - labelY = endY + labelOffset + pinX = x - labelOffset + pinY = y + portLength / 2 rotation = -90 break } @@ -142,22 +137,25 @@ export const SchematicChip: React.FC = ({ cx: endX, cy: endY, r: circleRadius, - strokeWidth: 0.01, + strokeWidth: 0.005, stroke: colorMap.schematic.component_outline, fill: colorMap.schematic.component_outline, }) - // Add pin label + // Add pin number if (pinNumber !== undefined) { - pinLabels.push({ - x: labelX, - y: labelY, + paths.push({ + type: "text", + cx: pinX, + cy: pinY, text: `${pinNumber}`, anchor: textAnchor, rotation: rotation, + strokeWidth: 0.005, + stroke: colorMap.schematic.pin_number, }) } - }) + } return ( <> @@ -167,24 +165,6 @@ export const SchematicChip: React.FC = ({ size={size} paths={paths as any} /> - {pinLabels.map((label, index) => ( - - ))} { pins: [29], direction: "left-to-right", }, + topSide: { + pins: [30], + direction: "left-to-right", + }, }} - schWidth={1} + schWidth={3} + schHeight={6} footprint="ssop28Db" pinLabels={{ "1": "TXD",