😁 Added too much stuff to explain!
This commit is contained in:
parent
df26cb6ddb
commit
900272a9e1
|
@ -18,6 +18,8 @@
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/neverix/html5-game-template#readme",
|
"homepage": "https://github.com/neverix/html5-game-template#readme",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/file-saver": "^2.0.1",
|
||||||
|
"@types/toastr": "^2.1.37",
|
||||||
"css-loader": "^2.1.0",
|
"css-loader": "^2.1.0",
|
||||||
"extract-text-webpack-plugin": "^4.0.0-beta.0",
|
"extract-text-webpack-plugin": "^4.0.0-beta.0",
|
||||||
"file-loader": "^3.0.1",
|
"file-loader": "^3.0.1",
|
||||||
|
@ -34,11 +36,14 @@
|
||||||
"webpack-dev-server": "^3.2.0"
|
"webpack-dev-server": "^3.2.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@eix/input": "git+https://github.com/eix-js/input.git",
|
||||||
"@eix/utils": "git+https://github.com/eix-js/utils.git",
|
"@eix/utils": "git+https://github.com/eix-js/utils.git",
|
||||||
|
"file-saver": "^2.0.2",
|
||||||
"haunted": "^4.3.0",
|
"haunted": "^4.3.0",
|
||||||
"lit-html": "^1.0.0",
|
"lit-html": "^1.0.0",
|
||||||
"lit-rx": "0.0.2",
|
"lit-rx": "0.0.2",
|
||||||
"prelude-ts": "^0.8.2",
|
"prelude-ts": "^0.8.2",
|
||||||
"rxjs": "^6.5.2"
|
"rxjs": "^6.5.2",
|
||||||
|
"toastr": "^2.1.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
@import "./toastr.scss";
|
||||||
|
|
||||||
html, body {
|
html, body {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -7,8 +9,52 @@ html, body {
|
||||||
}
|
}
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
background-color: #444444;
|
background-color: #222222;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: block;
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.createBar {
|
||||||
|
z-index:10;
|
||||||
|
position: absolute;
|
||||||
|
top:0px;
|
||||||
|
left:0px;
|
||||||
|
width:100%;
|
||||||
|
height:100%;
|
||||||
|
background-color: rgba(0,0,0,0.5);
|
||||||
|
transition: all 0.6s ease-in-out 0s;
|
||||||
|
.topContainer {
|
||||||
|
height: 30%;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
div{
|
||||||
|
height:25%;
|
||||||
|
width:75%;
|
||||||
|
input{
|
||||||
|
background-color: #444444;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
font-size: 250%;
|
||||||
|
height:100%;
|
||||||
|
width:100%;
|
||||||
|
padding: 1%;
|
||||||
|
font-family: "roboto";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
.createBar#shown{
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toasts{
|
||||||
|
background-color: #000000;
|
||||||
|
box-shadow: 0 0 0px black !important;
|
||||||
}
|
}
|
1
src/scss/toastr.scss
Normal file
1
src/scss/toastr.scss
Normal file
File diff suppressed because one or more lines are too long
|
@ -1,29 +1,98 @@
|
||||||
import { Vector } from "prelude-ts"
|
import { Vector } from "prelude-ts"
|
||||||
import { Subject, BehaviorSubject } from "rxjs";
|
import { Subject, BehaviorSubject, Subscription, timer } from "rxjs";
|
||||||
import { ComponentState } from "./interfaces";
|
import { ComponentState, activationContext } from "./interfaces";
|
||||||
import { map } from "rxjs/operators";
|
import { map, debounce } from "rxjs/operators";
|
||||||
import { Screen } from "../screen.ts";
|
import { Screen } from "../screen.ts";
|
||||||
|
import { ComponentTemplateStore } from "../componentManager/componentTemplateStore";
|
||||||
|
import { svg } from "lit-html";
|
||||||
|
import { subscribe } from "lit-rx";
|
||||||
|
import { Pin } from "../pin";
|
||||||
|
import { success, error } from "toastr"
|
||||||
|
import { alertOptions } from "../componentManager/alertOptions";
|
||||||
|
import { WireManager } from "../wires";
|
||||||
|
import { runCounter } from "./runCounter";
|
||||||
|
|
||||||
export class Component {
|
export class Component {
|
||||||
|
private static store = new ComponentTemplateStore()
|
||||||
private static screen = new Screen()
|
private static screen = new Screen()
|
||||||
|
private static wireManager = new WireManager()
|
||||||
|
private static lastId = runCounter.get() + 1
|
||||||
|
|
||||||
public position = new BehaviorSubject<number[]>(null)
|
public position = new BehaviorSubject<number[]>(null)
|
||||||
public scale = new BehaviorSubject<number[]>(null)
|
public scale = new BehaviorSubject<number[]>(null)
|
||||||
public clicked = false
|
public clicked = false
|
||||||
|
|
||||||
private mouserDelta: number[]
|
private mouserDelta: number[]
|
||||||
|
private strokeColor = "#888888"
|
||||||
|
private inputs: number
|
||||||
|
private outputs: number
|
||||||
|
private activation: (ctx: activationContext) => any
|
||||||
|
private subscriptions:Subscription[] = []
|
||||||
|
|
||||||
constructor(public activationType: string,
|
public inputPins: Pin[] = []
|
||||||
|
public outputPins: Pin[] = []
|
||||||
|
|
||||||
|
public id: number
|
||||||
|
|
||||||
|
constructor(private template: string,
|
||||||
position: [number, number] = [0, 0],
|
position: [number, number] = [0, 0],
|
||||||
scale: [number, number] = [0, 0]) {
|
scale: [number, number] = [0, 0],
|
||||||
|
id? : number) {
|
||||||
|
|
||||||
|
//set initial props
|
||||||
this.position.next(position)
|
this.position.next(position)
|
||||||
this.scale.next(scale)
|
this.scale.next(scale)
|
||||||
|
|
||||||
|
//set the correct id
|
||||||
|
this.id = (typeof id === "number") ? id : Component.lastId++
|
||||||
|
|
||||||
|
//load template
|
||||||
|
const data = Component.store.store.get(template)
|
||||||
|
|
||||||
|
if (!data)
|
||||||
|
throw new Error(`Template ${template} doesnt exist`)
|
||||||
|
|
||||||
|
this.inputs = data.inputs
|
||||||
|
this.outputs = data.outputs
|
||||||
|
|
||||||
|
this.inputPins = [...Array(this.inputs)].fill(true).map(val => new Pin(false, this))
|
||||||
|
this.outputPins = [...Array(this.outputs)].fill(true).map(val => new Pin(true, this))
|
||||||
|
|
||||||
|
this.activation = new Function(`return (ctx) => {
|
||||||
|
try{
|
||||||
|
${data.activation}
|
||||||
|
}
|
||||||
|
catch(err){
|
||||||
|
ctx.error(err,"",ctx.alertOptions)
|
||||||
|
}
|
||||||
|
}`)()
|
||||||
|
|
||||||
|
this.inputPins.forEach(val => {
|
||||||
|
const subscription = val.valueChanges.pipe(debounce(() => timer(1000 / 60)))
|
||||||
|
.subscribe(val => this.activate())
|
||||||
|
this.subscriptions.push(subscription)
|
||||||
|
})
|
||||||
|
|
||||||
|
this.activate()
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMouseUp(e: MouseEvent) {
|
public dispose(){
|
||||||
|
this.subscriptions.forEach(val => val.unsubscribe())
|
||||||
|
}
|
||||||
|
|
||||||
|
public handleMouseUp(e: MouseEvent) {
|
||||||
this.clicked = false
|
this.clicked = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private activate() {
|
||||||
|
this.activation({
|
||||||
|
outputs: this.outputPins,
|
||||||
|
inputs: this.inputPins,
|
||||||
|
succes: (mes: string) => { success(mes, "", alertOptions) },
|
||||||
|
error: (mes: string) => { error(mes, "", alertOptions) }
|
||||||
|
} as activationContext)
|
||||||
|
}
|
||||||
|
|
||||||
move(e: MouseEvent) {
|
move(e: MouseEvent) {
|
||||||
const mousePosition = Component.screen.getWorldPosition(e.clientX, e.clientY)
|
const mousePosition = Component.screen.getWorldPosition(e.clientX, e.clientY)
|
||||||
this.position.next(mousePosition.map((value, index) =>
|
this.position.next(mousePosition.map((value, index) =>
|
||||||
|
@ -40,11 +109,16 @@ export class Component {
|
||||||
this.clicked = true
|
this.clicked = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handlePinClick(e: MouseEvent, pin: Pin) {
|
||||||
|
Component.wireManager.add(pin)
|
||||||
|
}
|
||||||
|
|
||||||
get state(): ComponentState {
|
get state(): ComponentState {
|
||||||
return {
|
return {
|
||||||
position: this.position.value as [number, number],
|
position: this.position.value as [number, number],
|
||||||
scale: this.position.value as [number, number],
|
scale: this.scale.value as [number, number],
|
||||||
activationType: this.activationType
|
template: this.template,
|
||||||
|
id: this.id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +144,57 @@ export class Component {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromState(state:ComponentState){
|
pinsSvg(pinScale: number, pinLength = 20, mode = "input") {
|
||||||
return new Component(state.activationType, state.position, state.scale)
|
const stroke = 3
|
||||||
|
|
||||||
|
return ((mode === "input") ? this.inputPins : this.outputPins)
|
||||||
|
.map((val, index) => {
|
||||||
|
const y = subscribe(this.piny(mode === "input",index))
|
||||||
|
|
||||||
|
const x = subscribe(this.pinx(mode === "input",pinLength))
|
||||||
|
|
||||||
|
const linex = subscribe(this.x.pipe(map(val =>
|
||||||
|
val + ((mode === "input") ? -pinLength : pinLength + this.scale.value[0])
|
||||||
|
)))
|
||||||
|
|
||||||
|
const middleX = subscribe(this.x.pipe(map(val =>
|
||||||
|
val + this.scale.value[0] / 2
|
||||||
|
)))
|
||||||
|
|
||||||
|
return svg`
|
||||||
|
<line stroke=${this.strokeColor} y1=${y} y2=${y}
|
||||||
|
x1=${(mode === "input") ? linex : middleX}
|
||||||
|
x2=${(mode !== "input") ? linex : middleX}
|
||||||
|
stroke-width=${stroke}></line>
|
||||||
|
|
||||||
|
<circle fill=${subscribe(val.svgColor)}
|
||||||
|
stroke=${this.strokeColor}
|
||||||
|
r=${pinScale}
|
||||||
|
cx=${x}
|
||||||
|
cy=${y} stroke-width=${stroke}
|
||||||
|
@click=${(e: MouseEvent) => this.handlePinClick(e, val)}
|
||||||
|
></circle>
|
||||||
|
`})
|
||||||
|
}
|
||||||
|
|
||||||
|
public pinx(mode = true, pinLength = 15){
|
||||||
|
return this.x.pipe(
|
||||||
|
map(val => val + (
|
||||||
|
(mode) ?
|
||||||
|
-pinLength :
|
||||||
|
this.scale.value[0] + pinLength
|
||||||
|
))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public piny(mode = true, index: number){
|
||||||
|
const space = this.scale.value[1] / (mode ? this.inputs : this.outputs)
|
||||||
|
return this.y.pipe(
|
||||||
|
map(val => val + space * (2 * index + 1) / 2)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromState(state: ComponentState) {
|
||||||
|
return new Component(state.template, state.position, state.scale, state.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,15 @@
|
||||||
|
import { Pin } from "../pin";
|
||||||
|
|
||||||
export interface ComponentState {
|
export interface ComponentState {
|
||||||
position: [number,number]
|
position: [number,number]
|
||||||
scale: [number,number]
|
scale: [number,number]
|
||||||
activationType: string
|
template: string
|
||||||
|
id: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface activationContext {
|
||||||
|
inputs: Pin[]
|
||||||
|
outputs: Pin[]
|
||||||
|
succes: (mes: string) => any
|
||||||
|
error: (mes:string) => any
|
||||||
}
|
}
|
14
src/ts/common/component/runCounter.ts
Normal file
14
src/ts/common/component/runCounter.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import { Store } from "../store";
|
||||||
|
|
||||||
|
export const runCounter = {
|
||||||
|
store: new Store<number>("runCounter"),
|
||||||
|
get(){
|
||||||
|
return runCounter.store.get("main")
|
||||||
|
},
|
||||||
|
increase(){
|
||||||
|
runCounter.store.set("main", runCounter.store.get("main") + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!runCounter.get())
|
||||||
|
runCounter.store.set("main",1)
|
4
src/ts/common/componentManager/alertOptions.ts
Normal file
4
src/ts/common/componentManager/alertOptions.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
export const alertOptions = {
|
||||||
|
positionClass: "toast-bottom-right",
|
||||||
|
toastClass: "toasts"
|
||||||
|
}
|
|
@ -1,22 +1,222 @@
|
||||||
import { Singleton } from "@eix/utils";
|
import { Singleton } from "@eix/utils";
|
||||||
import { Component } from "../component/component";
|
import { Component } from "../component";
|
||||||
import { Subject } from "rxjs";
|
import { Subject, BehaviorSubject, fromEvent } from "rxjs";
|
||||||
import { svg, SVGTemplateResult } from "lit-html";
|
import { svg, SVGTemplateResult } from "lit-html";
|
||||||
import { subscribe } from "lit-rx";
|
import { subscribe } from "lit-rx";
|
||||||
import { Screen } from "../screen.ts";
|
import { Screen } from "../screen.ts";
|
||||||
import { MnanagerState } from "./interfaces";
|
import { ManagerState } from "./interfaces";
|
||||||
|
import { Store } from "../store";
|
||||||
|
import { KeyboardInput } from "@eix/input"
|
||||||
|
import { success, error } from "toastr"
|
||||||
|
import { ComponentTemplateStore } from "./componentTemplateStore";
|
||||||
|
import { alertOptions } from "./alertOptions";
|
||||||
|
import { WireManager } from "../wires";
|
||||||
|
import { runCounter } from "../component/runCounter";
|
||||||
|
import { Settings } from "../store/settings";
|
||||||
|
import { download } from "./download";
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
export class ComponentManager {
|
export class ComponentManager {
|
||||||
public components: Component[] = []
|
public components: Component[] = []
|
||||||
public svgs = new Subject<SVGTemplateResult[]>()
|
public svgs = new Subject<SVGTemplateResult>()
|
||||||
|
public placeholder = new BehaviorSubject("Create simulation")
|
||||||
|
|
||||||
|
private temporaryCommnad = ""
|
||||||
private onTop: Component
|
private onTop: Component
|
||||||
private clicked = false
|
private clicked = false
|
||||||
|
|
||||||
private screen = new Screen()
|
private screen = new Screen()
|
||||||
|
private wireManager = new WireManager()
|
||||||
|
private templateStore = new ComponentTemplateStore()
|
||||||
|
private settings = new Settings()
|
||||||
|
|
||||||
|
private commandHistoryStore = new Store<string>("commandHistory")
|
||||||
|
private store = new Store<ManagerState>("simulationStates")
|
||||||
|
|
||||||
|
private saveEvent = new KeyboardInput("s")
|
||||||
|
private createEvent = new KeyboardInput("m")
|
||||||
|
private closeInputEvent = new KeyboardInput("enter")
|
||||||
|
private ctrlEvent = new KeyboardInput("ctrl")
|
||||||
|
private palleteEvent = new KeyboardInput("p")
|
||||||
|
private shiftEvent = new KeyboardInput("shift")
|
||||||
|
private refreshEvent = new KeyboardInput("r")
|
||||||
|
private clearEvent = new KeyboardInput("c")
|
||||||
|
private upEvent = new KeyboardInput("up")
|
||||||
|
private downEvent = new KeyboardInput("down")
|
||||||
|
|
||||||
|
public name = "current"
|
||||||
|
public alertOptions = alertOptions
|
||||||
|
|
||||||
|
private commandHistory: string[] = []
|
||||||
|
private commands: {
|
||||||
|
[key: string]: (ctx: ComponentManager, args: string[], flags: string[]) => any
|
||||||
|
} = {
|
||||||
|
clear(ctx: ComponentManager) {
|
||||||
|
ctx.clear()
|
||||||
|
},
|
||||||
|
save(ctx: ComponentManager) {
|
||||||
|
ctx.save()
|
||||||
|
},
|
||||||
|
ls(ctx: ComponentManager) {
|
||||||
|
const data = ctx.store.ls()
|
||||||
|
const message = data.join("\n")
|
||||||
|
|
||||||
|
success(message, "", ctx.alertOptions)
|
||||||
|
},
|
||||||
|
help(ctx: ComponentManager) {
|
||||||
|
success(`Usage: <command> <br>
|
||||||
|
Where <command> is one of:
|
||||||
|
<ul>
|
||||||
|
${Object.keys(ctx.commands).map(val => `
|
||||||
|
<li>${val}</li>
|
||||||
|
`).join("")}
|
||||||
|
</ul>
|
||||||
|
`, "", ctx.alertOptions)
|
||||||
|
},
|
||||||
|
refresh(ctx: ComponentManager) {
|
||||||
|
ctx.refresh()
|
||||||
|
},
|
||||||
|
ctp: this.templateStore.commands.template,
|
||||||
|
settings: this.settings.commands,
|
||||||
|
download
|
||||||
|
}
|
||||||
|
private inputMode: string
|
||||||
|
|
||||||
|
public barAlpha = new BehaviorSubject<string>("0");
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
runCounter.increase()
|
||||||
|
|
||||||
this.svgs.next(this.render())
|
this.svgs.next(this.render())
|
||||||
|
|
||||||
|
this.refresh()
|
||||||
|
|
||||||
|
fromEvent(document.body, "keydown").subscribe((e: KeyboardEvent) => {
|
||||||
|
if (this.barAlpha.value == "1") {
|
||||||
|
const elem = document.getElementById("nameInput")
|
||||||
|
elem.focus()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
e.preventDefault()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
fromEvent(document.body, "keyup").subscribe((e: MouseEvent) => {
|
||||||
|
if (this.barAlpha.value === "1") {
|
||||||
|
if (this.closeInputEvent.value)
|
||||||
|
this.create()
|
||||||
|
else if (this.inputMode === "command") {
|
||||||
|
const elem = <HTMLInputElement>document.getElementById("nameInput")
|
||||||
|
if (this.upEvent.value) {
|
||||||
|
document.body.focus()
|
||||||
|
e.preventDefault()
|
||||||
|
const index = this.commandHistory.indexOf(elem.value)
|
||||||
|
|
||||||
|
if (index) {
|
||||||
|
//save drafts
|
||||||
|
if (index === -1)
|
||||||
|
this.temporaryCommnad = elem.value
|
||||||
|
|
||||||
|
const newIndex = (index === -1) ? this.commandHistory.length - 1 : index - 1
|
||||||
|
elem.value = this.commandHistory[newIndex]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.downEvent.value) {
|
||||||
|
document.body.focus()
|
||||||
|
e.preventDefault()
|
||||||
|
const index = this.commandHistory.indexOf(elem.value)
|
||||||
|
|
||||||
|
if (index > -1) {
|
||||||
|
const maxIndex = this.commandHistory.length - 1
|
||||||
|
elem.value = (index === maxIndex) ? this.temporaryCommnad : this.commandHistory[index + 1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (this.ctrlEvent.value) {
|
||||||
|
if (this.createEvent.value) {
|
||||||
|
this.preInput()
|
||||||
|
this.inputMode = "create"
|
||||||
|
this.placeholder.next("Create simulation")
|
||||||
|
}
|
||||||
|
else if (this.shiftEvent.value && this.palleteEvent.value) {
|
||||||
|
this.preInput()
|
||||||
|
this.inputMode = "command"
|
||||||
|
this.placeholder.next("Command palette")
|
||||||
|
}
|
||||||
|
else if (this.clearEvent.value) {
|
||||||
|
this.clear()
|
||||||
|
}
|
||||||
|
else if (this.saveEvent.value) {
|
||||||
|
this.save()
|
||||||
|
}
|
||||||
|
else if (this.refreshEvent.value) {
|
||||||
|
this.refresh()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
this.wireManager.update.subscribe(val => this.update())
|
||||||
|
}
|
||||||
|
|
||||||
|
preInput() {
|
||||||
|
const elem = <HTMLInputElement>document.getElementById("nameInput")
|
||||||
|
elem.value = ""
|
||||||
|
this.barAlpha.next("1")
|
||||||
|
}
|
||||||
|
|
||||||
|
create() {
|
||||||
|
const elem = <HTMLInputElement>document.getElementById("nameInput")
|
||||||
|
this.barAlpha.next("0")
|
||||||
|
|
||||||
|
if (this.inputMode == "create")
|
||||||
|
success(`Succesfully created simulation ${elem.value}`, "", this.alertOptions)
|
||||||
|
|
||||||
|
else if (this.inputMode == "command")
|
||||||
|
this.eval(elem.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
eval(command: string) {
|
||||||
|
if (!this.commandHistory.includes(command)) // no duplicates
|
||||||
|
this.commandHistory.push(command)
|
||||||
|
|
||||||
|
while (this.commandHistory.length > 10) // max of 10 elements
|
||||||
|
this.commandHistory.shift()
|
||||||
|
|
||||||
|
const words = command.split(" ")
|
||||||
|
|
||||||
|
if (words[0] in this.commands) {
|
||||||
|
const remaining = words.slice(1)
|
||||||
|
const flags = remaining.filter(val => val[0] == "-")
|
||||||
|
const args = remaining.filter(val => val[0] != "-")
|
||||||
|
this.commands[words[0]](this, args, flags)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
error(`Command ${words} doesn't exist. Run help to get a list of all commands.`,
|
||||||
|
"", this.alertOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
this.components = []
|
||||||
|
this.wireManager.dispose()
|
||||||
|
this.update()
|
||||||
|
|
||||||
|
success("Succesfully cleared all components", "", this.alertOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh() {
|
||||||
|
if (this.store.get(this.name)) {
|
||||||
|
this.loadState(this.store.get(this.name))
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const i of this.commandHistoryStore.ls())
|
||||||
|
this.commandHistory[Number(i)] = this.commandHistoryStore.get(i)
|
||||||
|
|
||||||
|
this.update()
|
||||||
|
|
||||||
|
success("Succesfully refreshed to the latest save", "", this.alertOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
update() {
|
update() {
|
||||||
|
@ -64,25 +264,32 @@ export class ComponentManager {
|
||||||
render() {
|
render() {
|
||||||
let toRemoveDuplicatesFor: Component
|
let toRemoveDuplicatesFor: Component
|
||||||
|
|
||||||
|
const size = 10
|
||||||
const result = this.components.map(component => svg`
|
const result = this.components.map(component => svg`
|
||||||
<rect width=${ subscribe(component.width)}
|
<g>
|
||||||
height=${ subscribe(component.height)}
|
${component.pinsSvg(10, 20)}
|
||||||
x=${ subscribe(component.x)}
|
${component.pinsSvg(10, 20, "output")}
|
||||||
y=${ subscribe(component.y)}
|
|
||||||
fill="red"
|
<rect width=${ subscribe(component.width)}
|
||||||
stroke="black"
|
height=${ subscribe(component.height)}
|
||||||
@mousedown=${ (e: MouseEvent) => component.handleClick(e)}
|
x=${ subscribe(component.x)}
|
||||||
@mouseup=${ (e: MouseEvent) => {
|
y=${ subscribe(component.y)}
|
||||||
|
fill="red"
|
||||||
|
stroke="black"
|
||||||
|
rx=20
|
||||||
|
ry=20
|
||||||
|
@mousedown=${ (e: MouseEvent) => component.handleClick(e)}
|
||||||
|
@mouseup=${(e: MouseEvent) => {
|
||||||
component.handleMouseUp(e)
|
component.handleMouseUp(e)
|
||||||
toRemoveDuplicatesFor = component
|
toRemoveDuplicatesFor = component
|
||||||
}}
|
}}></rect>
|
||||||
>
|
</g>
|
||||||
`);
|
`);
|
||||||
|
|
||||||
if (toRemoveDuplicatesFor)
|
if (toRemoveDuplicatesFor)
|
||||||
this.removeDuplicates(toRemoveDuplicatesFor)
|
this.removeDuplicates(toRemoveDuplicatesFor)
|
||||||
|
|
||||||
return result
|
return svg`${this.wireManager.svg} ${result}`
|
||||||
}
|
}
|
||||||
|
|
||||||
private removeDuplicates(component: Component) {
|
private removeDuplicates(component: Component) {
|
||||||
|
@ -95,21 +302,47 @@ export class ComponentManager {
|
||||||
.filter((val, index) => instances.indexOf(index) != -1)
|
.filter((val, index) => instances.indexOf(index) != -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
get state(): MnanagerState {
|
get state(): ManagerState {
|
||||||
const components = Array.from((new Set(this.components)).values())
|
const components = Array.from((new Set(this.components)).values())
|
||||||
return {
|
return {
|
||||||
components: components.map(value => value.state)
|
components: components.map(value => value.state),
|
||||||
|
position: this.screen.position as [number, number],
|
||||||
|
scale: this.screen.scale as [number, number],
|
||||||
|
wires: this.wireManager.state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadState(state:MnanagerState) {
|
public getComponentById(id: number) {
|
||||||
|
return this.components.find(val => val.id === id)
|
||||||
|
}
|
||||||
|
|
||||||
|
loadState(state: ManagerState) {
|
||||||
|
if (!state.wires) //old state
|
||||||
|
return
|
||||||
|
|
||||||
|
this.wireManager.dispose()
|
||||||
this.clicked = false
|
this.clicked = false
|
||||||
this.components = state.components.map(value => Component.fromState(value))
|
this.components = state.components.map(value => Component.fromState(value))
|
||||||
this.onTop = null
|
this.onTop = null
|
||||||
|
|
||||||
|
state.wires.forEach(val => {
|
||||||
|
this.wireManager.start = this.getComponentById(val.from.owner).outputPins[val.from.index]
|
||||||
|
this.wireManager.end = this.getComponentById(val.to.owner).inputPins[val.to.index]
|
||||||
|
this.wireManager.tryResolving()
|
||||||
|
})
|
||||||
|
|
||||||
|
this.screen.scale = state.scale
|
||||||
|
this.screen.position = state.position
|
||||||
|
|
||||||
this.update()
|
this.update()
|
||||||
}
|
}
|
||||||
|
|
||||||
save(){
|
save(name?: string) {
|
||||||
//TODO: implement
|
for (let i = 0; i < this.commandHistory.length; i++) {
|
||||||
|
const element = this.commandHistory[i];
|
||||||
|
this.commandHistoryStore.set(i.toString(), element)
|
||||||
|
}
|
||||||
|
this.store.set(name || this.name, this.state)
|
||||||
|
success("Saved the simulation succesfully!", "", this.alertOptions)
|
||||||
}
|
}
|
||||||
}
|
}
|
105
src/ts/common/componentManager/componentTemplateStore.ts
Normal file
105
src/ts/common/componentManager/componentTemplateStore.ts
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
import { Singleton } from "@eix/utils";
|
||||||
|
import { Store } from "../store";
|
||||||
|
import { ComponentTemplate } from "./interfaces";
|
||||||
|
import { ComponentManager } from "./componentManager";
|
||||||
|
import { success, error } from "toastr"
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
export class ComponentTemplateStore {
|
||||||
|
public store = new Store<ComponentTemplate>("componentTemplate")
|
||||||
|
|
||||||
|
public commands = {
|
||||||
|
template: (ctx: ComponentManager, args: string[], flags: string[]) => {
|
||||||
|
const command = args[0]
|
||||||
|
switch (command) {
|
||||||
|
case (undefined):
|
||||||
|
for (let i of flags) {
|
||||||
|
if (i === "--version" || i === "-v")
|
||||||
|
return success("1.0.1", "", ctx.alertOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
error(`Welcome to the component template program!
|
||||||
|
To get started, try running this basic commands:
|
||||||
|
${["--version", "ls"].map(val => `${val}`).join(" ")}
|
||||||
|
`, "", {
|
||||||
|
...ctx.alertOptions,
|
||||||
|
timeOut: 7500
|
||||||
|
})
|
||||||
|
|
||||||
|
break
|
||||||
|
case ("ls"):
|
||||||
|
success(`Here is a list of all the current registered component templates (including ics):
|
||||||
|
<ul>
|
||||||
|
${this.store.ls().map(val => `
|
||||||
|
<li>
|
||||||
|
${val}
|
||||||
|
</li>
|
||||||
|
`).join(" ")}
|
||||||
|
</ul>
|
||||||
|
`, "", ctx.alertOptions)
|
||||||
|
break
|
||||||
|
case ("info"):
|
||||||
|
if (!args[1])
|
||||||
|
return error("You need to specify a template name", "", ctx.alertOptions)
|
||||||
|
|
||||||
|
const data = this.store.get(args[1])
|
||||||
|
|
||||||
|
if (!data)
|
||||||
|
return error(`Component ${args[1]} doesnt exist`, "", ctx.alertOptions)
|
||||||
|
|
||||||
|
const showFunction = flags.find(value =>
|
||||||
|
value === "-sf" || value === "--showFunctions"
|
||||||
|
)
|
||||||
|
|
||||||
|
success(`
|
||||||
|
Name: ${data.name} <br>
|
||||||
|
Inputs: ${data.inputs} <br>
|
||||||
|
Outputs: ${data.outputs}
|
||||||
|
${showFunction ? `<br> Activation: ${data.activation}` : ""}
|
||||||
|
`, "", ctx.alertOptions)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
error(`${command} is not a valid command for the template program`, "", ctx.alertOptions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.store.set("buffer", {
|
||||||
|
inputs: 1,
|
||||||
|
outputs: 1,
|
||||||
|
name: "buffer",
|
||||||
|
version: "1.0.0",
|
||||||
|
activation: `
|
||||||
|
ctx.outputs[0].value = ctx.inputs[0].value
|
||||||
|
`.trim()
|
||||||
|
})
|
||||||
|
this.store.set("not", {
|
||||||
|
inputs: 1,
|
||||||
|
outputs: 1,
|
||||||
|
name: "buffer",
|
||||||
|
version: "1.0.0",
|
||||||
|
activation: `
|
||||||
|
ctx.outputs[0].value = !ctx.inputs[0].value
|
||||||
|
`.trim()
|
||||||
|
})
|
||||||
|
this.store.set("and", {
|
||||||
|
inputs: 2,
|
||||||
|
outputs: 1,
|
||||||
|
name: "and",
|
||||||
|
version: "1.0.0",
|
||||||
|
activation: `
|
||||||
|
ctx.outputs[0].value = ctx.inputs[0].value && ctx.inputs[1].value
|
||||||
|
`.trim()
|
||||||
|
})
|
||||||
|
this.store.set("true", {
|
||||||
|
inputs: 0,
|
||||||
|
outputs: 1,
|
||||||
|
name: "true",
|
||||||
|
version: "1.0.0",
|
||||||
|
activation: `
|
||||||
|
ctx.outputs[0].value = true
|
||||||
|
`.trim()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
31
src/ts/common/componentManager/download.ts
Normal file
31
src/ts/common/componentManager/download.ts
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import { ComponentManager } from "./componentManager";
|
||||||
|
import { success } from "toastr"
|
||||||
|
import { saveAs } from "file-saver"
|
||||||
|
|
||||||
|
const version = "1.0.0"
|
||||||
|
|
||||||
|
export const download = (ctx: ComponentManager, args: string[], flags:string[]) => {
|
||||||
|
//important flags
|
||||||
|
for (let i of flags) {
|
||||||
|
if (i === "--version" || i === "-v")
|
||||||
|
return success(`${version}`, "", ctx.alertOptions)
|
||||||
|
else if (i === "--help" || i === "-h")
|
||||||
|
return success(`Run "download" to download the save as a json file.
|
||||||
|
Flags:<ul>
|
||||||
|
<li>-v or --version to get the version.</li>
|
||||||
|
<li>-h or --help to get help (ou are reading that right now)</li>
|
||||||
|
<li>-s or --save to automatically save before downloading</li>
|
||||||
|
</ul>`,"",ctx.alertOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
const command = args[0]
|
||||||
|
|
||||||
|
if (command === undefined){
|
||||||
|
if (flags.includes("-s") || flags.includes("--save"))
|
||||||
|
ctx.save()
|
||||||
|
|
||||||
|
const data = JSON.stringify(ctx.state)
|
||||||
|
saveAs(new Blob([data]), `${ctx.name}.json`)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,17 @@
|
||||||
import { ComponentState } from "../component/interfaces";
|
import { ComponentState } from "../component/interfaces";
|
||||||
|
import { WireState } from "../wires/interface";
|
||||||
|
|
||||||
export interface MnanagerState {
|
export interface ManagerState {
|
||||||
components: ComponentState[]
|
components: ComponentState[]
|
||||||
|
scale: [number,number]
|
||||||
|
position: [number,number]
|
||||||
|
wires: WireState
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ComponentTemplate {
|
||||||
|
name: string
|
||||||
|
version: string
|
||||||
|
activation: string
|
||||||
|
inputs: number
|
||||||
|
outputs: number
|
||||||
}
|
}
|
1
src/ts/common/pin/index.ts
Normal file
1
src/ts/common/pin/index.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export * from "./pin"
|
65
src/ts/common/pin/pin.ts
Normal file
65
src/ts/common/pin/pin.ts
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
import { BehaviorSubject, Subject, Subscription } from "rxjs";
|
||||||
|
import { map } from "rxjs/operators"
|
||||||
|
import clamp from "../clamp/clamp";
|
||||||
|
import { Component } from "../component";
|
||||||
|
|
||||||
|
export class Pin {
|
||||||
|
private static lastId = 0
|
||||||
|
|
||||||
|
public pair: Pin
|
||||||
|
private subscriptions: Subscription[] = []
|
||||||
|
|
||||||
|
public id: number
|
||||||
|
public _value = 0
|
||||||
|
public color = new BehaviorSubject<[number, number, number, number]>([0, 0, 0,0])
|
||||||
|
public memory: any = {}
|
||||||
|
public valueChanges = new Subject<number>()
|
||||||
|
|
||||||
|
public svgColor = this.color.pipe(map(val =>
|
||||||
|
`rgb(${val.join(",")})`
|
||||||
|
))
|
||||||
|
|
||||||
|
constructor(public allowWrite = true, public of: Component) {
|
||||||
|
this.setValue(0)
|
||||||
|
this.id = Pin.lastId++
|
||||||
|
}
|
||||||
|
|
||||||
|
get value() {
|
||||||
|
return this._value
|
||||||
|
}
|
||||||
|
|
||||||
|
set value(value: number) {
|
||||||
|
if (!this.allowWrite) return
|
||||||
|
this.setValue(value)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public setValue(value: number) {
|
||||||
|
this._value = clamp(value, 0, 1)
|
||||||
|
this.valueChanges.next(this._value)
|
||||||
|
|
||||||
|
const color: [number, number, number, number] = (value > 0.5) ?
|
||||||
|
[255, 216, 20, 1] :
|
||||||
|
[90, 90, 90, 1]
|
||||||
|
|
||||||
|
this.color.next((this.pair) ? color : [0,0,0,0])
|
||||||
|
}
|
||||||
|
|
||||||
|
public bindTo(pin: Pin){
|
||||||
|
this.pair = pin
|
||||||
|
const subscription = pin.valueChanges.subscribe(val => this.setValue(val))
|
||||||
|
|
||||||
|
this.subscriptions.push(subscription)
|
||||||
|
}
|
||||||
|
|
||||||
|
public unbind(pin: Pin) {
|
||||||
|
if (this.pair == pin){
|
||||||
|
this.pair = null
|
||||||
|
this.subscriptions.forEach(val => val.unsubscribe())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public update(){
|
||||||
|
this.setValue(this._value)
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,13 +10,13 @@ export class Screen {
|
||||||
viewBox = combineLatest(this.width, this.height).pipe(map((values: [number,number]) =>
|
viewBox = combineLatest(this.width, this.height).pipe(map((values: [number,number]) =>
|
||||||
this.getViewBox(...values)
|
this.getViewBox(...values)
|
||||||
));
|
));
|
||||||
|
|
||||||
private scrollStep = 1.3
|
public position = [0, 0]
|
||||||
private position = [0, 0]
|
|
||||||
public scale = [2, 2]
|
public scale = [2, 2]
|
||||||
|
|
||||||
private zoomLimits: [number,number] = [0.1,10]
|
private zoomLimits: [number,number] = [0.1,10]
|
||||||
|
|
||||||
|
private scrollStep = 1.3
|
||||||
public mousePosition = [this.width.value / 2, this.height.value / 2]
|
public mousePosition = [this.width.value / 2, this.height.value / 2]
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|
1
src/ts/common/store/index.ts
Normal file
1
src/ts/common/store/index.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export * from "./store"
|
29
src/ts/common/store/settings.ts
Normal file
29
src/ts/common/store/settings.ts
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import { Singleton } from "@eix/utils";
|
||||||
|
import { ComponentManager } from "../componentManager";
|
||||||
|
import { success, error } from "toastr"
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
export class Settings {
|
||||||
|
version = "1.0.0"
|
||||||
|
|
||||||
|
commands = (ctx: ComponentManager, args: string[], flags: string[]) => {
|
||||||
|
//important flags
|
||||||
|
for (let i of flags) {
|
||||||
|
if (i === "--version" || i === "-v")
|
||||||
|
return success(`${this.version}`, "", ctx.alertOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
const command = args[0]
|
||||||
|
|
||||||
|
if (command === undefined)
|
||||||
|
return success(
|
||||||
|
`Welcome to the settings cli. You can use this to tweak settings in any way imaginable!`,
|
||||||
|
"",
|
||||||
|
ctx.alertOptions)
|
||||||
|
|
||||||
|
//nothing here
|
||||||
|
error(`Commands ${args} couldnt be found`,"",ctx.alertOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
}
|
28
src/ts/common/store/store.ts
Normal file
28
src/ts/common/store/store.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
export class Store<T> {
|
||||||
|
constructor(private name: string){ }
|
||||||
|
|
||||||
|
get(key:string):T{
|
||||||
|
const data = localStorage[`${this.name}/${key}`]
|
||||||
|
|
||||||
|
if(data)
|
||||||
|
return JSON.parse(data).value
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
set(key:string,value:T){
|
||||||
|
localStorage[`${this.name}/${key}`] = JSON.stringify({ value })
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
ls() {
|
||||||
|
let keys = []
|
||||||
|
|
||||||
|
for (const i in localStorage){
|
||||||
|
if (i.indexOf(this.name) == 0)
|
||||||
|
keys.push(i.substr(this.name.length + 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
}
|
1
src/ts/common/wires/index.ts
Normal file
1
src/ts/common/wires/index.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export * from "./wireManager"
|
12
src/ts/common/wires/interface.ts
Normal file
12
src/ts/common/wires/interface.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
export interface WireStateVal {
|
||||||
|
from: {
|
||||||
|
owner: number
|
||||||
|
index: number
|
||||||
|
},
|
||||||
|
to: {
|
||||||
|
owner: number
|
||||||
|
index: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type WireState = WireStateVal[]
|
15
src/ts/common/wires/wire.ts
Normal file
15
src/ts/common/wires/wire.ts
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import { Pin } from "../pin";
|
||||||
|
|
||||||
|
export class Wire {
|
||||||
|
constructor (public input:Pin,public output:Pin){
|
||||||
|
this.output.bindTo(this.input)
|
||||||
|
this.input.pair = this.output
|
||||||
|
this.input.update()
|
||||||
|
this.output.update()
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose(){
|
||||||
|
this.output.unbind(this.input)
|
||||||
|
this.input.pair = null
|
||||||
|
}
|
||||||
|
}
|
81
src/ts/common/wires/wireManager.ts
Normal file
81
src/ts/common/wires/wireManager.ts
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
import { Singleton } from "@eix/utils";
|
||||||
|
import { Pin } from "../pin";
|
||||||
|
import { Wire } from "./wire";
|
||||||
|
import { svg } from "lit-html";
|
||||||
|
import { subscribe } from "lit-rx";
|
||||||
|
import { ComponentManager } from "../componentManager";
|
||||||
|
import { Observable, Subject } from "rxjs";
|
||||||
|
import { WireState, WireStateVal } from "./interface";
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
export class WireManager {
|
||||||
|
public start: Pin
|
||||||
|
public end: Pin
|
||||||
|
|
||||||
|
private wires: Wire[] = []
|
||||||
|
|
||||||
|
public update = new Subject<boolean>()
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
public add(data: Pin) {
|
||||||
|
if (data.allowWrite) //output
|
||||||
|
this.start = data
|
||||||
|
else
|
||||||
|
this.end = data
|
||||||
|
|
||||||
|
this.tryResolving()
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose(){
|
||||||
|
for (let i of this.wires)
|
||||||
|
i.dispose()
|
||||||
|
|
||||||
|
this.wires = []
|
||||||
|
}
|
||||||
|
|
||||||
|
public tryResolving() {
|
||||||
|
if (this.start && this.end && this.start != this.end) {
|
||||||
|
if (this.canBind(this.start, this.end)) {
|
||||||
|
this.wires.push(new Wire(this.start, this.end))
|
||||||
|
this.start = null
|
||||||
|
this.end = null
|
||||||
|
this.update.next(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private canBind(start: Pin, end: Pin) {
|
||||||
|
if (this.wires.find(val => val.output === end))
|
||||||
|
return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
get svg() {
|
||||||
|
return this.wires.map(val => {
|
||||||
|
const i = val.input.of
|
||||||
|
const o = val.output.of
|
||||||
|
return svg`
|
||||||
|
<line x1=${subscribe(i.pinx(false, 20))}
|
||||||
|
x2=${subscribe(o.pinx(true, 20))}
|
||||||
|
y1=${subscribe(i.piny(false,i.outputPins.indexOf(val.input)))}
|
||||||
|
y2=${subscribe(o.piny(true,o.inputPins.indexOf(val.output)))}
|
||||||
|
stroke=${subscribe(val.input.svgColor)}
|
||||||
|
>
|
||||||
|
</line>
|
||||||
|
`})
|
||||||
|
}
|
||||||
|
|
||||||
|
get state() {
|
||||||
|
return this.wires.map((val):WireStateVal => ({
|
||||||
|
from: {
|
||||||
|
owner: val.input.of.id,
|
||||||
|
index: val.input.of.outputPins.indexOf(val.input)
|
||||||
|
},
|
||||||
|
to: {
|
||||||
|
owner: val.output.of.id,
|
||||||
|
index: val.output.of.inputPins.indexOf(val.output)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,37 +4,59 @@ import { Screen } from "./common/screen.ts";
|
||||||
import { Component } from "./common/component";
|
import { Component } from "./common/component";
|
||||||
import { FunctionStore } from "./common/activation/activationStore";
|
import { FunctionStore } from "./common/activation/activationStore";
|
||||||
import { ComponentManager } from "./common/componentManager";
|
import { ComponentManager } from "./common/componentManager";
|
||||||
|
import { map } from "rxjs/operators";
|
||||||
|
|
||||||
const screen = new Screen()
|
const screen = new Screen()
|
||||||
|
|
||||||
const test = new FunctionStore()
|
|
||||||
test.register("buffer",(data) => {
|
|
||||||
return true;
|
|
||||||
})
|
|
||||||
|
|
||||||
const manager = new ComponentManager()
|
const manager = new ComponentManager()
|
||||||
manager.components.push(new Component("none",[200,100],[200,30]))
|
manager.components.push(new Component("and",[200,100],[100,100]))
|
||||||
manager.components.push(new Component("none",[300,100],[200,30]))
|
manager.components.push(new Component("not",[200,500],[100,100]))
|
||||||
manager.components.push(new Component("none",[400,100],[200,30]))
|
manager.components.push(new Component("true",[200,500],[100,100]))
|
||||||
manager.components.push(new Component("none",[500,100],[200,30]))
|
|
||||||
manager.components.push(new Component("none",[600,100],[200,30]))
|
|
||||||
manager.update()
|
manager.update()
|
||||||
|
|
||||||
console.log(manager.state)
|
|
||||||
|
const handleEvent = <T>(e:T,func:(e:T) => any) => {
|
||||||
|
if (manager.barAlpha.value == "0")
|
||||||
|
func(e)
|
||||||
|
else if (manager.barAlpha.value == "1"
|
||||||
|
&& (e as unknown as MouseEvent).type == "mousedown"
|
||||||
|
&& (e as unknown as MouseEvent).target != document.getElementById("nameInput"))
|
||||||
|
manager.barAlpha.next("0")
|
||||||
|
}
|
||||||
|
|
||||||
render(html`
|
render(html`
|
||||||
<svg height=${ subscribe(screen.height) } width=${ subscribe(screen.width) }
|
<div @mousemove=${(e:MouseEvent) => handleEvent(e,(e:MouseEvent) => {
|
||||||
@mousemove=${(e:MouseEvent) => {
|
|
||||||
manager.handleMouseMove(e)
|
manager.handleMouseMove(e)
|
||||||
screen.updateMouse(e)
|
screen.updateMouse(e)
|
||||||
}}
|
})}
|
||||||
viewBox=${subscribe(screen.viewBox)}
|
@mousedown=${(e:MouseEvent) => handleEvent(e,(e:MouseEvent) =>
|
||||||
@mousedown=${(e:MouseEvent) => manager.handleMouseDown(e)}
|
manager.handleMouseDown(e)
|
||||||
@mouseup=${(e:MouseEvent) => manager.handleMouseUp(e)}
|
)}
|
||||||
@wheel=${(e:WheelEvent) => screen.handleScroll(e)}
|
@mouseup=${(e:MouseEvent) => handleEvent(e,(e:MouseEvent) =>
|
||||||
>
|
manager.handleMouseUp(e)
|
||||||
${ subscribe(manager.svgs) }
|
)}
|
||||||
</svg>
|
@wheel=${(e:MouseEvent) => handleEvent(e,(e:WheelEvent) =>
|
||||||
|
screen.handleScroll(e)
|
||||||
|
)}>
|
||||||
|
|
||||||
|
<div id=${subscribe(manager.barAlpha.pipe(map(val =>
|
||||||
|
(val == "1") ? "shown" : ""
|
||||||
|
)))}
|
||||||
|
class=createBar>
|
||||||
|
<div class="topContainer">
|
||||||
|
<div>
|
||||||
|
<input name="ComponentName" id="nameInput"
|
||||||
|
placeholder=${subscribe(manager.placeholder)}
|
||||||
|
></input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<svg height=${ subscribe(screen.height) }
|
||||||
|
width=${ subscribe(screen.width) }
|
||||||
|
viewBox=${subscribe(screen.viewBox)}>
|
||||||
|
${ subscribe(manager.svgs) }
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
`, document.body)
|
`, document.body)
|
||||||
|
|
||||||
manager.update()
|
manager.update()
|
Loading…
Reference in a new issue