diff --git a/src/main/angular/src/app/editor/Point.ts b/src/main/angular/src/app/editor/Point.ts new file mode 100644 index 0000000..423d151 --- /dev/null +++ b/src/main/angular/src/app/editor/Point.ts @@ -0,0 +1,20 @@ +import {Junction} from "./junction/Junction"; + +export class Point { + + constructor( + readonly x: number, + readonly y: number, + ) { + // + } + + static fromEvent(event: MouseEvent) { + return new Point(event.offsetX, event.offsetY); + } + + static fromJunction(j: Junction) { + return new Point(j.pixelX, j.pixelY); + } + +} diff --git a/src/main/angular/src/app/editor/breadboard/breadboard.component.html b/src/main/angular/src/app/editor/breadboard/breadboard.component.html index 2657cad..60f69bf 100644 --- a/src/main/angular/src/app/editor/breadboard/breadboard.component.html +++ b/src/main/angular/src/app/editor/breadboard/breadboard.component.html @@ -1,4 +1,4 @@ - + @@ -6,27 +6,52 @@ {{ asBattery(part).voltageStr }} - - + + {{ asBattery(part).currentStr }} - {{ asBattery(part).voltageStr }} + {{ asLight(part).voltageStr }} - {{ asBattery(part).currentStr }} + {{ asLight(part).currentStr }} - - + + + + + + + + + + + + + + + diff --git a/src/main/angular/src/app/editor/breadboard/breadboard.component.less b/src/main/angular/src/app/editor/breadboard/breadboard.component.less index 1753674..33a3c51 100644 --- a/src/main/angular/src/app/editor/breadboard/breadboard.component.less +++ b/src/main/angular/src/app/editor/breadboard/breadboard.component.less @@ -8,9 +8,16 @@ user-select: none; .part { + .background { fill: lightgray; } + + .partWire { + stroke-width: 5px; + stroke: black; + } + } .part:not(:has(.junction:hover)):hover { @@ -40,8 +47,23 @@ } .wire { - stroke-width: 5px; + stroke-width: 9px; stroke: black; + stroke-linecap: round; + pointer-events: none; + } + + .wireOpen { + stroke: blue; + stroke-dasharray: 5px 15px; + } + + .wireEnd { + stroke: green; + } + + .wireDuplicate { + stroke: red; } .junction { diff --git a/src/main/angular/src/app/editor/breadboard/breadboard.component.ts b/src/main/angular/src/app/editor/breadboard/breadboard.component.ts index dd7fe88..11d0333 100644 --- a/src/main/angular/src/app/editor/breadboard/breadboard.component.ts +++ b/src/main/angular/src/app/editor/breadboard/breadboard.component.ts @@ -3,6 +3,9 @@ import {NgClass, NgForOf, NgIf} from '@angular/common'; import {Part} from '../parts/Part'; import {Battery} from '../parts/battery/Battery'; import {Light} from '../parts/light/Light'; +import {Junction} from '../junction/Junction'; +import {Wire} from '../wire/Wire'; +import {Point} from '../Point'; @Component({ selector: 'app-board', @@ -16,11 +19,29 @@ import {Light} from '../parts/light/Light'; }) export class BreadboardComponent { - parts: Part[] = [ - new Battery(1, 1, 3, 0.5), - new Light(1, 5, 3, 3, 0.5), + private battery = new Battery(1, 1, 3, 0.5); + + private light = new Light(1, 5, 3, 1.5, 0.5); + + protected readonly parts: Part[] = [this.battery, this.light]; + + protected readonly wires: Wire[] = [ + new Wire(this.battery.minus, this.light.a), + new Wire(this.battery.plus, this.light.b), ]; + protected wireCursor: Point | null = null; + + protected wireStart: Point | null = null; + + protected wireEnd: Point | null = null; + + protected wireStartJunction: Junction | null = null; + + protected wireEndJunction: Junction | null = null; + + protected wireEndDuplicate: boolean = false; + asBattery(part: Part): Battery { return part as Battery; } @@ -37,4 +58,75 @@ export class BreadboardComponent { return part instanceof Light; } + mouseMove($event: MouseEvent) { + this.wireCursor = Point.fromEvent($event); + } + + mouseUp($event: MouseEvent) { + if ($event.button === 0) { + this.wireReset(); + } + } + + junctionMouseDown(j: Junction, $event: MouseEvent) { + if ($event.button === 0) { + this.wireCursor = Point.fromEvent($event); + this.wireStart = Point.fromJunction(j); + this.wireStartJunction = j; + } + } + + junctionMouseEnter(j: Junction, $event: MouseEvent) { + if ($event.button === 0 && this.wireStartJunction !== null) { + if (this.wireStartJunction === j) { + this.wireEndReset(); + } else { + this.wireEnd = Point.fromJunction(j); + this.wireEndJunction = j; + this.wireEndDuplicate = this.wires.some(w => (w.start === this.wireStartJunction && w.end === this.wireEndJunction) || (w.start === this.wireEndJunction && w.end === this.wireStartJunction)); + } + } + } + + junctionMouseLeave(j: Junction, $event: MouseEvent) { + if ($event.button === 0 && this.wireStartJunction !== null && this.wireEndJunction === j) { + this.wireEndReset(); + } + } + + junctionMouseUp($event: MouseEvent) { + if ($event.button === 0) { + if (this.wireStartJunction !== null && this.wireEndJunction !== null) { + this.wireConnect(this.wireStartJunction, this.wireEndJunction); + } + this.wireReset(); + } + } + + private wireConnect(start: Junction, end: Junction) { + if (start === end) { + console.log("Not connecting junction with itself."); + return; + } + if (this.wireEndDuplicate) { + console.log("Not connecting duplicate wire."); + return; + } + const wire = new Wire(start, end); + console.log("Wire created: ", wire); + this.wires.push(wire); + } + + private wireReset() { + this.wireStart = null; + this.wireStartJunction = null; + this.wireEndReset(); + } + + private wireEndReset() { + this.wireEnd = null; + this.wireEndJunction = null; + this.wireEndDuplicate = false; + } + } diff --git a/src/main/angular/src/app/editor/parseColor.ts b/src/main/angular/src/app/editor/colorHelpers.ts similarity index 57% rename from src/main/angular/src/app/editor/parseColor.ts rename to src/main/angular/src/app/editor/colorHelpers.ts index cb7bac9..48e5713 100644 --- a/src/main/angular/src/app/editor/parseColor.ts +++ b/src/main/angular/src/app/editor/colorHelpers.ts @@ -24,3 +24,13 @@ export function parseColor(color: string): { r: number; g: number; b: number } { return {r, g, b}; } + +export function fadeGrayToYellow(factor: number, fromColor: any, toColor: any): string { + fromColor = parseColor(fromColor); + toColor = parseColor(toColor); + factor = Math.max(0, Math.min(100, factor)); + const r = Math.round(fromColor.r + factor * (toColor.r - fromColor.r)); + const g = Math.round(fromColor.g + factor * (toColor.g - fromColor.g)); + const b = Math.round(fromColor.b + factor * (toColor.b - fromColor.b)); + return `rgb(${r}, ${g}, ${b})`; +} diff --git a/src/main/angular/src/app/editor/fadeGrayToYellow.ts b/src/main/angular/src/app/editor/fadeGrayToYellow.ts deleted file mode 100644 index 4b3dcbb..0000000 --- a/src/main/angular/src/app/editor/fadeGrayToYellow.ts +++ /dev/null @@ -1,11 +0,0 @@ -import {parseColor} from './parseColor'; - -export function fadeGrayToYellow(factor: number, fromColor: any, toColor: any): string { - fromColor = parseColor(fromColor); - toColor = parseColor(toColor); - factor = Math.max(0, Math.min(100, factor)); - const r = Math.round(fromColor.r + factor * (toColor.r - fromColor.r)); - const g = Math.round(fromColor.g + factor * (toColor.g - fromColor.g)); - const b = Math.round(fromColor.b + factor * (toColor.b - fromColor.b)); - return `rgb(${r}, ${g}, ${b})`; -} diff --git a/src/main/angular/src/app/editor/junction/Junction.ts b/src/main/angular/src/app/editor/junction/Junction.ts index 44d4bf3..8c2adc1 100644 --- a/src/main/angular/src/app/editor/junction/Junction.ts +++ b/src/main/angular/src/app/editor/junction/Junction.ts @@ -2,28 +2,43 @@ export const JUNCTION_RADIUS_PERCENT = 15; export class Junction { + readonly id: string = self.crypto.randomUUID(); + + readonly percentX: number; + + readonly percentY: number; + constructor( - readonly x: number, - readonly y: number, + percentX: number, + percentY: number, readonly name: string, ) { - // + this.percentX = percentX - JUNCTION_RADIUS_PERCENT; + this.percentY = percentY - JUNCTION_RADIUS_PERCENT; } - get xP(): string { - return (this.x - JUNCTION_RADIUS_PERCENT) + '%'; + private boundingBox(next: (b: DOMRect) => number): number { + const b = document.getElementById(this.id)?.getBoundingClientRect(); + if (!b) { + return 0; + } + return next(b); } - get yP(): string { - return (this.y - JUNCTION_RADIUS_PERCENT) + '%'; + get pixelX(): number { + return this.boundingBox(b => b.x + b.width / 2); } - get wP(): string { - return (JUNCTION_RADIUS_PERCENT * 2) + '%'; + get pixelY(): number { + return this.boundingBox(b => b.y + b.height / 2); } - get hP(): string { - return (JUNCTION_RADIUS_PERCENT * 2) + '%'; + get percentW(): number { + return (JUNCTION_RADIUS_PERCENT * 2); + } + + get percentH(): number { + return (JUNCTION_RADIUS_PERCENT * 2); } } diff --git a/src/main/angular/src/app/editor/parts/Part.ts b/src/main/angular/src/app/editor/parts/Part.ts index 90ccd26..5797b00 100644 --- a/src/main/angular/src/app/editor/parts/Part.ts +++ b/src/main/angular/src/app/editor/parts/Part.ts @@ -1,51 +1,52 @@ -import {Junction} from '../junction/Junction'; import {PartType} from './PartType'; +import {Junction} from '../junction/Junction'; export const RASTER = 50; export abstract class Part { protected constructor( - readonly x: number, - readonly y: number, readonly type: PartType, - readonly junctions: Junction[], - readonly w: number = 3, - readonly h: number = 3, + readonly rasterX: number, + readonly rasterY: number, + readonly rasterW: number = 3, + readonly rasterH: number = 3, ) { // } - get xR(): number { - return this.x * RASTER; + abstract get junctions(): Junction[]; + + get x(): number { + return this.rasterX * RASTER; } - get yR(): number { - return this.y * RASTER; + get y(): number { + return this.rasterY * RASTER; } - get wR(): number { - return this.w * RASTER; + get w(): number { + return this.rasterW * RASTER; } - get hR(): number { - return this.h * RASTER; + get h(): number { + return this.rasterH * RASTER; } get xP(): string { - return this.xR + 'px'; + return this.x + 'px'; } get yP(): string { - return this.yR + 'px'; + return this.y + 'px'; } get wP(): string { - return this.wR + 'px'; + return this.w + 'px'; } get hP(): string { - return this.hR + 'px'; + return this.h + 'px'; } ngClass(): string[] { diff --git a/src/main/angular/src/app/editor/parts/battery/Battery.ts b/src/main/angular/src/app/editor/parts/battery/Battery.ts index f787c0b..0e5c7c0 100644 --- a/src/main/angular/src/app/editor/parts/battery/Battery.ts +++ b/src/main/angular/src/app/editor/parts/battery/Battery.ts @@ -5,21 +5,21 @@ import {siPrefix} from '../../siPrefix'; export class Battery extends Part { + readonly minus: Junction = new Junction(15, 50, "-"); + + readonly plus: Junction = new Junction(85, 50, "+"); + constructor( - x: number, - y: number, + rasterX: number, + rasterY: number, readonly voltage: number, public current: number, ) { - super( - x, - y, - PartType.Battery, - [ - new Junction(15, 50, "-"), - new Junction(85, 50, "+"), - ] - ); + super(PartType.Battery, rasterX, rasterY); + } + + override get junctions(): Junction[] { + return [this.minus, this.plus]; } get voltageStr(): string { diff --git a/src/main/angular/src/app/editor/parts/light/Light.ts b/src/main/angular/src/app/editor/parts/light/Light.ts index f52d43a..777f0cf 100644 --- a/src/main/angular/src/app/editor/parts/light/Light.ts +++ b/src/main/angular/src/app/editor/parts/light/Light.ts @@ -2,26 +2,27 @@ import {Part} from "../Part"; import {Junction} from '../../junction/Junction'; import {PartType} from '../PartType'; import {siPrefix} from '../../siPrefix'; -import {fadeGrayToYellow} from '../../fadeGrayToYellow'; + +import {fadeGrayToYellow} from '../../colorHelpers'; export class Light extends Part { + readonly a = new Junction(15, 50, "a"); + + readonly b = new Junction(85, 50, "b"); + constructor( - x: number, - y: number, + rasterX: number, + rasterY: number, readonly voltageMax: number, readonly voltage: number, public current: number, ) { - super( - x, - y, - PartType.Light, - [ - new Junction(15, 50, "a"), - new Junction(85, 50, "b"), - ] - ); + super(PartType.Light, rasterX, rasterY); + } + + override get junctions(): Junction[] { + return [this.a, this.b]; } get defect(): boolean { diff --git a/src/main/angular/src/app/editor/wire/Wire.ts b/src/main/angular/src/app/editor/wire/Wire.ts new file mode 100644 index 0000000..1645f6b --- /dev/null +++ b/src/main/angular/src/app/editor/wire/Wire.ts @@ -0,0 +1,12 @@ +import {Junction} from "../junction/Junction"; + +export class Wire { + + constructor( + readonly start: Junction, + readonly end: Junction, + ) { + // + } + +}