feat: enhance wire offset calculation to maintain pin connections with L-shaped stubs
parent
96131e7451
commit
336f0460cd
160
README.md
160
README.md
|
|
@ -14,36 +14,72 @@ Every star counts and helps make this project better! You can also support the p
|
|||
|
||||
## Screenshots
|
||||
|
||||

|
||||

|
||||
|
||||
Arduino emulator with Monaco code editor and visual simulator with wokwi-elements
|
||||
Raspberry Pi Pico simulation — ADC read test with two potentiometers, Serial Monitor showing live output, and compilation console at the bottom.
|
||||
|
||||

|
||||

|
||||
|
||||
Interactive component properties dialog and segment-based wire editing
|
||||
Arduino Uno driving an ILI9341 240×320 TFT display via SPI — rendering a real-time graphics demo using Adafruit_GFX + Adafruit_ILI9341.
|
||||
|
||||

|
||||
|
||||
Library Manager loads the full Arduino library index on open — browse and install libraries without typing first.
|
||||
|
||||

|
||||
|
||||
Component Picker showing 48 available components with visual previews, search, and category filters (Boards, Displays, Input, Motors, Output, Passive, Sensors).
|
||||
|
||||
## Features
|
||||
|
||||
### Code Editing
|
||||
- **Monaco Editor** — Full C++ editor with syntax highlighting, autocomplete, minimap, and dark theme
|
||||
- **Arduino compilation** via `arduino-cli` backend — compile sketches to `.hex` files
|
||||
- **Arduino compilation** via `arduino-cli` backend — compile sketches to `.hex` / `.uf2` files
|
||||
- **Compile / Run / Stop / Reset** toolbar buttons with status messages
|
||||
- **Compilation console** — resizable output panel at the bottom of the editor showing full compiler output, warnings, and errors
|
||||
|
||||
### AVR8 Simulation (avr8js)
|
||||
### Multi-Board Support
|
||||
- **Arduino Uno** (ATmega328p) — full AVR8 emulation via avr8js
|
||||
- **Raspberry Pi Pico** (RP2040) — full RP2040 emulation via rp2040js, compiled with arduino-pico core
|
||||
- Board selector in the toolbar — switch boards without restarting
|
||||
|
||||
### AVR8 Simulation (Arduino Uno)
|
||||
- **Real ATmega328p emulation** at 16 MHz using avr8js
|
||||
- **Intel HEX parser** with checksum verification
|
||||
- **Full GPIO support** — PORTB (pins 8-13), PORTC (A0-A5), PORTD (pins 0-7)
|
||||
- **Timer0 peripheral** support
|
||||
- **USART (Serial)** support
|
||||
- **Timer0/Timer1/Timer2** peripheral support (enables `millis()`, `delay()`, PWM via `analogWrite()`)
|
||||
- **USART (Serial)** — full transmit and receive support
|
||||
- **ADC** — `analogRead()` on pins A0-A5, voltage injection from UI components
|
||||
- **SPI** — hardware SPI peripheral (enables ILI9341, SD card, etc.)
|
||||
- **I2C (TWI)** — hardware I2C with virtual device bus (DS1307, temp sensor, EEPROM)
|
||||
- **~60 FPS simulation loop** with `requestAnimationFrame` (~267k cycles/frame)
|
||||
- **Speed control** — adjustable from 0.1x to 10x
|
||||
- **Single-step debugging** API
|
||||
- **External pin state injection** for input components (buttons, potentiometers)
|
||||
- **PWM monitoring** — reads OCR registers each frame to drive PWM-capable components
|
||||
|
||||
### RP2040 Simulation (Raspberry Pi Pico)
|
||||
- **Real RP2040 emulation** via rp2040js at 133 MHz
|
||||
- **UART0** serial output captured and displayed in Serial Monitor
|
||||
- **ADC** — 12-bit, 3.3V reference on GPIO 26-29 (A0-A3)
|
||||
- **I2C** bus with virtual device support
|
||||
- Automatic `#define Serial Serial1` injection at compile time to route serial output to emulated UART
|
||||
|
||||
### Serial Monitor
|
||||
- **Live serial output** — displays characters as the sketch sends them via `Serial.print()`
|
||||
- **Baud rate indicator** — automatically detects the speed set by `Serial.begin()` reading hardware registers in real time — no manual configuration needed
|
||||
- **Send data** to the Arduino RX pin from the UI
|
||||
- **Line ending selector** — None, Newline, Carriage Return, or Both
|
||||
- **Autoscroll** with toggle
|
||||
- **Resizable panel** — drag the handle to adjust height
|
||||
|
||||
### ILI9341 TFT Display Simulation
|
||||
- **Full SPI command decoding** — CASET, PASET, RAMWR, SWRESET, DISPON, MADCTL, and more
|
||||
- **RGB-565 pixel rendering** directly to an HTML Canvas element in real time
|
||||
- **240×320 resolution** with full framebuffer support
|
||||
- Compatible with Adafruit_GFX + Adafruit_ILI9341 libraries
|
||||
|
||||
### Component System (48+ Components)
|
||||
- **48 electronic components** auto-discovered from wokwi-elements source code
|
||||
- **Component picker modal** with search bar, category filtering, and live wokwi-element previews as thumbnails
|
||||
- **9 component categories**: Boards (4), Sensors (6), Displays (3), Input (5), Output (5), Motors (2), Passive (4), Other (19)
|
||||
- **Component picker modal** with search bar, category filtering (Boards, Displays, Input, Motors, Output, Passive, Sensors), and live wokwi-element previews as thumbnails
|
||||
- **Dynamic component rendering** from build-time metadata (TypeScript AST parser extracts `@customElement` tags, `@property` decorators, and pin counts)
|
||||
- **Drag-and-drop repositioning** on the simulation canvas
|
||||
- **Component rotation** in 90° increments
|
||||
|
|
@ -54,27 +90,38 @@ Interactive component properties dialog and segment-based wire editing
|
|||
|
||||
### Part Simulation Behaviors
|
||||
- **LED** — pin state drives LED on/off
|
||||
- **RGB LED** — digital HIGH/LOW mapped to individual R/G/B channels
|
||||
- **Pushbutton** — press/release events inject active-LOW pin state into simulation
|
||||
- **Potentiometer** — reads element value (0-1023), converts to voltage, injects into ADC channel
|
||||
- **LCD 1602 & LCD 2004** — Full HD44780 controller emulation:
|
||||
- 4-bit mode protocol (high nibble first, then low nibble)
|
||||
- DDRAM with proper line address mapping
|
||||
- Commands: Clear Display, Return Home, Entry Mode Set, Display On/Off, Cursor/Display Shift, Function Set
|
||||
- Initialization sequence handling
|
||||
- Enable pin falling-edge detection for data latching
|
||||
- **RGB LED** — digital HIGH/LOW and PWM (`analogWrite`) mapped to R/G/B channels
|
||||
- **Pushbutton / 6mm pushbutton** — press/release events inject active-LOW pin state
|
||||
- **Slide switch** — toggle between HIGH and LOW
|
||||
- **DIP Switch 8** — 8 independent toggles, each driving its own pin
|
||||
- **Potentiometer** — reads slider value (0-1023), converts to voltage (5V for AVR, 3.3V for RP2040), injects into ADC
|
||||
- **Slide potentiometer** — same as rotary, with configurable min/max range
|
||||
- **Analog joystick** — two ADC axes (VRX/VRY) + button press
|
||||
- **Photoresistor sensor** — injects mid-range voltage on AO pin; reacts to element input events
|
||||
- **Servo** — reads Timer1 OCR1A/ICR1 registers to calculate pulse width and maps to 0-180° angle
|
||||
- **Buzzer** — Web Audio API tone generation, frequency derived from Timer2 OCR2A/TCCR2B registers
|
||||
- **LED Bar Graph** — 10 individual LEDs driven by pins A1-A10
|
||||
- **7-Segment Display** — segments A-G + DP driven by individual pins
|
||||
- **LCD 1602 & LCD 2004** — full HD44780 controller emulation in 4-bit mode (RS, E, D4-D7 pins)
|
||||
- **ILI9341 TFT** — full SPI display simulation (see above)
|
||||
|
||||
### Wire System
|
||||
- **Wire creation** — click a pin to start, click another pin to connect
|
||||
- **Real-time preview** — dashed green wire with L-shaped orthogonal routing while creating
|
||||
- **Orthogonal wire rendering** — no diagonal paths
|
||||
- **Segment-based wire editing** — hover to highlight, drag segments perpendicular to their orientation
|
||||
- **Smooth dragging** with `requestAnimationFrame`
|
||||
- **8 signal-type wire colors**: Red (VCC), Black (GND), Blue (Analog), Green (Digital), Purple (PWM), Gold (I2C), Orange (SPI), Cyan (USART)
|
||||
- **Automatic overlap offset** — parallel wires are offset symmetrically (6px spacing)
|
||||
- **Auto-update positions** — wire endpoints recalculate when components move
|
||||
- **Grid snapping** (20px grid)
|
||||
|
||||
### Library Manager
|
||||
- **Loads full library index on open** — no need to type first; shows spinner while fetching
|
||||
- **Live search with debounce** — filter while typing (400ms delay)
|
||||
- **Install libraries** directly from the UI via arduino-cli
|
||||
- **Installed tab** — see all installed libraries with versions
|
||||
- **Cross-reference** — installed libraries show "INSTALLED" badge in search results
|
||||
|
||||
### Example Projects
|
||||
- **8 built-in example projects** with full code, components, and wire definitions:
|
||||
|
||||
|
|
@ -92,10 +139,16 @@ Interactive component properties dialog and segment-based wire editing
|
|||
- **Examples gallery** with category and difficulty filters
|
||||
- **One-click loading** — loads code, components, and wires into the editor and simulator
|
||||
|
||||
### UI / Layout
|
||||
- **Resizable panels** — drag the vertical divider between editor and simulator
|
||||
- **Resizable bottom panels** — Serial Monitor and compilation console share the same draggable handle; both start at the same height (200px)
|
||||
- **Compilation console at the bottom** — output appears below the code editor, not between the toolbar and the code
|
||||
- **Serial Monitor** opens automatically when simulation starts
|
||||
|
||||
### Wokwi Libraries (Local Clones)
|
||||
- **wokwi-elements** — 48+ electronic web components (Lit-based Web Components)
|
||||
- **avr8js** — AVR8 CPU emulator
|
||||
- **rp2040js** — RP2040 emulator (cloned, for future use)
|
||||
- **rp2040js** — RP2040 emulator
|
||||
- **Build-time metadata generation** — TypeScript AST parser reads wokwi-elements source to generate component metadata automatically
|
||||
|
||||
## Prerequisites
|
||||
|
|
@ -131,6 +184,11 @@ arduino-cli core update-index
|
|||
arduino-cli core install arduino:avr
|
||||
```
|
||||
|
||||
**For Raspberry Pi Pico support:**
|
||||
```bash
|
||||
arduino-cli core install rp2040:rp2040
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
### Option A: Docker (Recommended)
|
||||
|
|
@ -214,14 +272,15 @@ The frontend will be available at:
|
|||
## Usage
|
||||
|
||||
1. Open http://localhost:5173 in your browser
|
||||
2. Write Arduino code in the editor (a Blink example is loaded by default)
|
||||
3. Click **Compile** to compile the code via the backend
|
||||
4. Click **Run** to start real AVR8 CPU simulation
|
||||
5. Watch LEDs, LCDs, and other components react in real time
|
||||
6. Click on components to view properties or assign pin mappings
|
||||
7. Double-click components to open the pin selector
|
||||
2. Select a board (Arduino Uno or Raspberry Pi Pico) from the toolbar
|
||||
3. Write Arduino code in the editor (a Blink example is loaded by default)
|
||||
4. Click **Compile** to compile the code via the backend
|
||||
5. Click **Run** to start simulation — the Serial Monitor opens automatically
|
||||
6. Watch LEDs, LCDs, TFT displays, and other components react in real time
|
||||
7. Click components to view properties or assign pin mappings
|
||||
8. Click pins to create wires connecting components
|
||||
9. Browse **Examples** to load pre-built projects (Blink, Traffic Light, Simon Says, LCD, etc.)
|
||||
9. Use the **Library Manager** to install Arduino libraries
|
||||
10. Browse **Examples** to load pre-built projects
|
||||
|
||||
## Project Structure
|
||||
|
||||
|
|
@ -232,17 +291,16 @@ openwokwi/
|
|||
│ │ ├── components/
|
||||
│ │ │ ├── ComponentPickerModal.tsx # Component search & picker
|
||||
│ │ │ ├── DynamicComponent.tsx # Generic wokwi component renderer
|
||||
│ │ │ ├── components-wokwi/ # Legacy React wrappers
|
||||
│ │ │ ├── editor/ # Monaco Editor + toolbar
|
||||
│ │ │ ├── examples/ # Examples gallery
|
||||
│ │ │ └── simulator/ # Canvas, wires, pins, dialogs
|
||||
│ │ │ ├── editor/ # Monaco Editor + toolbar + compilation console
|
||||
│ │ │ └── simulator/ # Canvas, wires, pins, Serial Monitor, dialogs
|
||||
│ │ ├── simulation/
|
||||
│ │ │ ├── AVRSimulator.ts # AVR8 CPU emulator wrapper
|
||||
│ │ │ ├── PinManager.ts # Pin-to-component mapping
|
||||
│ │ │ └── parts/ # Part behaviors (LED, LCD, etc.)
|
||||
│ │ │ ├── RP2040Simulator.ts # RP2040 emulator wrapper
|
||||
│ │ │ ├── PinManager.ts # Pin-to-component mapping + PWM
|
||||
│ │ │ └── parts/ # Part behaviors (LED, LCD, ILI9341, servo, buzzer...)
|
||||
│ │ ├── store/ # Zustand state management
|
||||
│ │ ├── services/ # API clients & ComponentRegistry
|
||||
│ │ ├── types/ # TypeScript types (wires, components)
|
||||
│ │ ├── types/ # TypeScript types (wires, components, metadata)
|
||||
│ │ ├── utils/ # Hex parser, wire routing, pin calc
|
||||
│ │ └── pages/ # EditorPage, ExamplesPage
|
||||
│ └── public/
|
||||
|
|
@ -251,14 +309,14 @@ openwokwi/
|
|||
├── backend/ # FastAPI + Python
|
||||
│ └── app/
|
||||
│ ├── main.py # Entry point, CORS config
|
||||
│ ├── api/routes/compile.py # POST /api/compile, GET /api/compile/boards
|
||||
│ ├── api/routes/compile.py # POST /api/compile
|
||||
│ ├── api/routes/libraries.py # Library search, install, list
|
||||
│ └── services/arduino_cli.py # arduino-cli subprocess wrapper
|
||||
│
|
||||
├── wokwi-libs/ # Cloned Wokwi repositories
|
||||
│ ├── wokwi-elements/ # 48+ Web Components (Lit)
|
||||
│ ├── avr8js/ # AVR8 CPU Emulator
|
||||
│ ├── rp2040js/ # RP2040 Emulator (future)
|
||||
│ └── wokwi-features/ # Features and documentation
|
||||
│ └── rp2040js/ # RP2040 Emulator
|
||||
│
|
||||
├── scripts/
|
||||
│ └── generate-component-metadata.ts # AST parser for component discovery
|
||||
|
|
@ -266,8 +324,10 @@ openwokwi/
|
|||
├── doc/
|
||||
│ ├── ARCHITECTURE.md # Detailed architecture documentation
|
||||
│ ├── WOKWI_LIBS.md # Wokwi integration documentation
|
||||
│ ├── SETUP_COMPLETE.md # Project status overview
|
||||
│ └── examples/ # Example screenshots
|
||||
│ ├── img1.png # Screenshot: RP2040 + Serial Monitor
|
||||
│ ├── img2.png # Screenshot: ILI9341 TFT simulation
|
||||
│ ├── img3.png # Screenshot: Library Manager
|
||||
│ └── img4.png # Screenshot: Component Picker
|
||||
│
|
||||
├── CLAUDE.md # AI assistant guidance
|
||||
└── update-wokwi-libs.bat # Update local Wokwi libraries
|
||||
|
|
@ -282,7 +342,6 @@ openwokwi/
|
|||
- **Monaco Editor** — Code editor (VS Code engine)
|
||||
- **Zustand** 5 — State management
|
||||
- **React Router** 7 — Client-side routing
|
||||
- **Axios** — HTTP client
|
||||
|
||||
### Backend
|
||||
- **FastAPI** — Python web framework
|
||||
|
|
@ -291,17 +350,16 @@ openwokwi/
|
|||
|
||||
### Simulation & Components
|
||||
- **avr8js** — Real AVR8 ATmega328p emulator (local clone)
|
||||
- **rp2040js** — RP2040 emulator (local clone)
|
||||
- **wokwi-elements** — 48+ electronic web components built with Lit (local clone)
|
||||
- **rp2040js** — RP2040 emulator (local clone, for future use)
|
||||
|
||||
## Planned Features
|
||||
|
||||
- **Serial Monitor** — UI for reading USART output from the simulation
|
||||
- **Project Persistence** — Save/load projects with SQLite
|
||||
- **Undo/Redo** — Edit history for code and circuit changes
|
||||
- **Multi-board Support** — Runtime board switching (Mega, Nano, ESP32)
|
||||
- **Wire Validation** — Electrical validation and error highlighting
|
||||
- **Export/Import** — Share projects as files
|
||||
- **More boards** — ESP32, Arduino Mega, Arduino Nano
|
||||
|
||||
## Update Wokwi Libraries
|
||||
|
||||
|
|
@ -337,9 +395,9 @@ See [WOKWI_LIBS.md](doc/WOKWI_LIBS.md) for more details about Wokwi integration.
|
|||
- Check CORS logs in browser console
|
||||
|
||||
### Compilation errors
|
||||
- Check backend console for arduino-cli logs
|
||||
- Check the compilation console output at the bottom of the editor
|
||||
- Make sure Arduino code is valid
|
||||
- Verify you have the `arduino:avr` core installed
|
||||
- Verify you have the correct core installed (`arduino:avr` for Uno, `rp2040:rp2040` for Pico)
|
||||
|
||||
### LED doesn't blink
|
||||
- Check port listeners are firing (browser console logs)
|
||||
|
|
@ -349,6 +407,10 @@ See [WOKWI_LIBS.md](doc/WOKWI_LIBS.md) for more details about Wokwi integration.
|
|||
- Ensure `avrInstruction()` is being called in the execution loop
|
||||
- Check hex file was loaded correctly
|
||||
|
||||
### Serial Monitor shows nothing
|
||||
- Make sure your sketch calls `Serial.begin()` before `Serial.print()`
|
||||
- Check the baud rate indicator appears in the Serial Monitor header after the simulation starts
|
||||
|
||||
## Contributing
|
||||
|
||||
This is an open-source project. Suggestions, bug reports, and pull requests are welcome!
|
||||
|
|
@ -362,6 +424,6 @@ MIT
|
|||
- [Wokwi](https://wokwi.com) — Project inspiration
|
||||
- [avr8js](https://github.com/wokwi/avr8js) — AVR8 emulator
|
||||
- [wokwi-elements](https://github.com/wokwi/wokwi-elements) — Electronic web components
|
||||
- [rp2040js](https://github.com/wokwi/rp2040js) — RP2040 emulator
|
||||
- [arduino-cli](https://github.com/arduino/arduino-cli) — Arduino compiler
|
||||
- [Monaco Editor](https://microsoft.github.io/monaco-editor/) — Code editor
|
||||
|
||||
|
|
|
|||
BIN
doc/img1.png
BIN
doc/img1.png
Binary file not shown.
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 146 KiB |
BIN
doc/img2.png
BIN
doc/img2.png
Binary file not shown.
|
Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 136 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 186 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 153 KiB |
|
|
@ -218,44 +218,76 @@ export function calculateWireOffsets(wires: Wire[]): Map<string, number> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Apply offset to wire points (perpendicular to wire direction)
|
||||
* Apply offset to wire points (perpendicular to wire direction).
|
||||
*
|
||||
* Instead of moving the endpoints (which would visually disconnect the wire from its
|
||||
* pins), we keep the true pin positions fixed and insert short stub segments that
|
||||
* travel from each pin to the offset path, forming an L-shaped attachment at both ends.
|
||||
*
|
||||
* Example (horizontal wire, offset = +6):
|
||||
* Before: pin ────────────────── pin
|
||||
* After: pin (stub)
|
||||
* │ ──────────────── │
|
||||
* (stub) pin
|
||||
*/
|
||||
export function applyOffsetToWire(wire: Wire, offset: number): Wire {
|
||||
if (offset === 0) return wire;
|
||||
|
||||
// Clone the wire
|
||||
const offsetWire: Wire = {
|
||||
...wire,
|
||||
start: { ...wire.start },
|
||||
end: { ...wire.end },
|
||||
controlPoints: wire.controlPoints ? [...wire.controlPoints] : [],
|
||||
};
|
||||
// Determine primary direction from the first segment of the path
|
||||
const firstControlOrEnd =
|
||||
wire.controlPoints && wire.controlPoints.length > 0
|
||||
? wire.controlPoints[0]
|
||||
: wire.end;
|
||||
|
||||
// Apply offset to start and end points
|
||||
// Determine primary direction (first segment)
|
||||
const firstPoint = offsetWire.start;
|
||||
const secondPoint = offsetWire.controlPoints && offsetWire.controlPoints.length > 0
|
||||
? offsetWire.controlPoints[0]
|
||||
: offsetWire.end;
|
||||
const isHorizontalFirst =
|
||||
Math.abs(firstControlOrEnd.x - wire.start.x) >=
|
||||
Math.abs(firstControlOrEnd.y - wire.start.y);
|
||||
|
||||
const isVertical = Math.abs(secondPoint.x - firstPoint.x) < Math.abs(secondPoint.y - firstPoint.y);
|
||||
// True pin positions (never moved)
|
||||
const pinStart = { x: wire.start.x, y: wire.start.y };
|
||||
const pinEnd = { x: wire.end.x, y: wire.end.y };
|
||||
|
||||
// Apply offset perpendicular to direction
|
||||
if (isVertical) {
|
||||
// Vertical wire: offset in X
|
||||
offsetWire.start.x += offset;
|
||||
offsetWire.end.x += offset;
|
||||
offsetWire.controlPoints?.forEach(point => {
|
||||
point.x += offset;
|
||||
});
|
||||
} else {
|
||||
// Horizontal wire: offset in Y
|
||||
offsetWire.start.y += offset;
|
||||
offsetWire.end.y += offset;
|
||||
offsetWire.controlPoints?.forEach(point => {
|
||||
point.y += offset;
|
||||
});
|
||||
// Offset intermediate points perpendicular to the primary direction
|
||||
const shiftedControlPoints = (wire.controlPoints || []).map(cp => ({
|
||||
...cp,
|
||||
x: isHorizontalFirst ? cp.x : cp.x + offset,
|
||||
y: isHorizontalFirst ? cp.y + offset : cp.y,
|
||||
}));
|
||||
|
||||
// Compute where the offset path actually starts/ends
|
||||
// (the point on the parallel track immediately after the pin stub)
|
||||
const offsetStart = isHorizontalFirst
|
||||
? { x: pinStart.x, y: pinStart.y + offset }
|
||||
: { x: pinStart.x + offset, y: pinStart.y };
|
||||
|
||||
const offsetEnd = isHorizontalFirst
|
||||
? { x: pinEnd.x, y: pinEnd.y + offset }
|
||||
: { x: pinEnd.x + offset, y: pinEnd.y };
|
||||
|
||||
// Build new control points:
|
||||
// stub from pinStart → offsetStart, then the shifted intermediates, then stub from offsetEnd → pinEnd
|
||||
// We only need to add extra stubs when they are non-zero length.
|
||||
const newControlPoints: typeof wire.controlPoints = [];
|
||||
|
||||
// Leading stub end-point (where the offset path begins)
|
||||
if (offsetStart.x !== pinStart.x || offsetStart.y !== pinStart.y) {
|
||||
newControlPoints.push({ id: `${wire.id}-stub-s`, ...offsetStart });
|
||||
}
|
||||
|
||||
return offsetWire;
|
||||
// Shifted original control points
|
||||
for (const cp of shiftedControlPoints) {
|
||||
newControlPoints.push(cp);
|
||||
}
|
||||
|
||||
// Trailing stub start-point (where the offset path rejoins the pin)
|
||||
if (offsetEnd.x !== pinEnd.x || offsetEnd.y !== pinEnd.y) {
|
||||
newControlPoints.push({ id: `${wire.id}-stub-e`, ...offsetEnd });
|
||||
}
|
||||
|
||||
return {
|
||||
...wire,
|
||||
start: { ...wire.start, x: pinStart.x, y: pinStart.y },
|
||||
end: { ...wire.end, x: pinEnd.x, y: pinEnd.y },
|
||||
controlPoints: newControlPoints,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue