Add support for constants
This commit is contained in:
parent
7d9d2a2d78
commit
96e2184a24
6
build.js
6
build.js
|
@ -43,7 +43,11 @@ const ctx = await esbuild.context({
|
||||||
})
|
})
|
||||||
|
|
||||||
if (serve) {
|
if (serve) {
|
||||||
const { port, host } = await ctx.serve({ servedir: 'dist' })
|
await ctx.watch()
|
||||||
|
const { port, host } = await ctx.serve({
|
||||||
|
servedir: 'dist',
|
||||||
|
fallback: 'dist/index.html'
|
||||||
|
})
|
||||||
console.log(`Serving on ${host}:${port}`)
|
console.log(`Serving on ${host}:${port}`)
|
||||||
} else {
|
} else {
|
||||||
await ctx.rebuild()
|
await ctx.rebuild()
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"dev": "ESBUILD_SERVE=1 node ./build.js",
|
||||||
"build": "node ./build.js",
|
"build": "node ./build.js",
|
||||||
"check": "tsc"
|
"check": "tsc"
|
||||||
},
|
},
|
||||||
|
|
|
@ -33,8 +33,10 @@ async function main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new EventSource('/esbuild').addEventListener('change', () => location.reload())
|
||||||
|
|
||||||
// Call entry
|
// Call entry
|
||||||
main().catch(error => {
|
main().catch((error) => {
|
||||||
// if the error handling error has an error, log that error
|
// if the error handling error has an error, log that error
|
||||||
console.error('Error loading app', error)
|
console.error('Error loading app', error)
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Simulation, SimulationEnv } from '../../simulation/classes/Simulation'
|
import { SimulationEnv } from '../../simulation/classes/Simulation'
|
||||||
import { PinState } from '../../simulation/classes/Pin'
|
import { PinState } from '../../simulation/classes/Pin'
|
||||||
|
|
||||||
export interface Context {
|
export interface Context {
|
||||||
|
@ -6,8 +6,12 @@ export interface Context {
|
||||||
setProperty: (name: string, value: unknown) => void
|
setProperty: (name: string, value: unknown) => void
|
||||||
get: (index: number) => PinState
|
get: (index: number) => PinState
|
||||||
set: (index: number, state: PinState) => void
|
set: (index: number, state: PinState) => void
|
||||||
|
getOutput: (index: number) => PinState
|
||||||
getBinary: (index: number) => number
|
getBinary: (index: number) => number
|
||||||
setBinary: (index: number, value: number, bits: number) => void
|
printBinary: (value: number, bits?: number) => string
|
||||||
|
printHex: (value: number, length?: number) => string
|
||||||
|
setBinary: (index: number, value: number, bits?: number) => void
|
||||||
|
getOutputBinary: (index: number) => number
|
||||||
invertBinary: (value: number) => number
|
invertBinary: (value: number) => number
|
||||||
color: (color: string) => void
|
color: (color: string) => void
|
||||||
innerText: (value: string) => void
|
innerText: (value: string) => void
|
||||||
|
|
|
@ -46,6 +46,10 @@ div .gate-prop-container {
|
||||||
&.visible {
|
&.visible {
|
||||||
margin: 1rem;
|
margin: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&>* {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
div .gate-prop-group-container {
|
div .gate-prop-group-container {
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import './GateProperties.scss'
|
import './GateProperties.scss'
|
||||||
import React, { ChangeEvent } from 'react'
|
import { ChangeEvent } from 'react'
|
||||||
import { getRendererSafely } from '../helpers/getRendererSafely'
|
import { getRendererSafely } from '../helpers/getRendererSafely'
|
||||||
import { Property, RawProp, isGroup } from '../../simulation/types/GateTemplate'
|
import { Property, RawProp, isGroup } from '../../simulation/types/GateTemplate'
|
||||||
import { useObservable } from 'rxjs-hooks'
|
import { useObservable } from 'rxjs-hooks'
|
||||||
import Divider from '@material-ui/core/Divider'
|
|
||||||
import TextField from '@material-ui/core/TextField'
|
import TextField from '@material-ui/core/TextField'
|
||||||
import CheckBox from '@material-ui/core/Checkbox'
|
import CheckBox from '@material-ui/core/Checkbox'
|
||||||
import { open, id } from '../subjects/LogicGatePropsSubjects'
|
import { open, id } from '../subjects/LogicGatePropsSubjects'
|
||||||
|
@ -70,15 +69,13 @@ const GateRawProperty = ({
|
||||||
// rerender when the external checkbox changes
|
// rerender when the external checkbox changes
|
||||||
const external = useObservable(
|
const external = useObservable(
|
||||||
() =>
|
() =>
|
||||||
gate.props.external.pipe(
|
gate.props.external.pipe(map((value) => value && name !== 'external')),
|
||||||
map((value) => value && name !== 'external')
|
|
||||||
),
|
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
|
||||||
const displayableName = `${name[0].toUpperCase()}${name.slice(1)}${
|
const displayableName = `${name[0].toUpperCase()}${name.slice(1)}${
|
||||||
external && name !== 'label' ? ' (default value)' : ''
|
external && name !== 'label' ? ' (default value)' : ''
|
||||||
}:`
|
}${raw.description == undefined ? '' : ` ${raw.description}`}:`
|
||||||
|
|
||||||
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
|
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
const target = e.target as HTMLInputElement
|
const target = e.target as HTMLInputElement
|
||||||
|
@ -112,11 +109,7 @@ const GateRawProperty = ({
|
||||||
return emptyInput
|
return emptyInput
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (raw.type === 'number' || raw.type === 'text' || raw.type === 'string') {
|
||||||
raw.type === 'number' ||
|
|
||||||
raw.type === 'text' ||
|
|
||||||
raw.type === 'string'
|
|
||||||
) {
|
|
||||||
return (
|
return (
|
||||||
<TextField
|
<TextField
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
|
@ -124,7 +117,6 @@ const GateRawProperty = ({
|
||||||
value={outputSnapshot}
|
value={outputSnapshot}
|
||||||
type={raw.type}
|
type={raw.type}
|
||||||
multiline={raw.type === 'string'}
|
multiline={raw.type === 'string'}
|
||||||
rowsMax={7}
|
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
} else if (raw.type === 'boolean') {
|
} else if (raw.type === 'boolean') {
|
||||||
|
@ -145,9 +137,7 @@ const GateRawProperty = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`gate-prop-container ${
|
className={`gate-prop-container ${input !== emptyInput ? 'visible' : ''}`}
|
||||||
input !== emptyInput ? 'visible' : ''
|
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
{input}
|
{input}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -20,6 +20,7 @@ import comparatorTemplate from './templates/comparator'
|
||||||
import bitMergerTemplate from './templates/bitMerger'
|
import bitMergerTemplate from './templates/bitMerger'
|
||||||
import bitSplitterTemplate from './templates/bitSplitter'
|
import bitSplitterTemplate from './templates/bitSplitter'
|
||||||
import incrementorTemplate from './templates/incrementor'
|
import incrementorTemplate from './templates/incrementor'
|
||||||
|
import constantTemplate from './templates/constant'
|
||||||
|
|
||||||
export const defaultSimulationName = 'default'
|
export const defaultSimulationName = 'default'
|
||||||
export const baseTemplates: DeepPartial<GateTemplate>[] = [
|
export const baseTemplates: DeepPartial<GateTemplate>[] = [
|
||||||
|
@ -42,7 +43,8 @@ export const baseTemplates: DeepPartial<GateTemplate>[] = [
|
||||||
comparatorTemplate,
|
comparatorTemplate,
|
||||||
bitMergerTemplate,
|
bitMergerTemplate,
|
||||||
bitSplitterTemplate,
|
bitSplitterTemplate,
|
||||||
incrementorTemplate
|
incrementorTemplate,
|
||||||
|
constantTemplate
|
||||||
]
|
]
|
||||||
|
|
||||||
export const baseSave: RendererState = {
|
export const baseSave: RendererState = {
|
||||||
|
|
60
src/modules/saving/templates/constant.ts
Normal file
60
src/modules/saving/templates/constant.ts
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
import { PartialTemplate } from '../types/PartialTemplate'
|
||||||
|
import { categories } from '../data/categories'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The template of the button gate
|
||||||
|
*/
|
||||||
|
const constTemplate: PartialTemplate = {
|
||||||
|
metadata: {
|
||||||
|
name: 'constant'
|
||||||
|
},
|
||||||
|
material: {
|
||||||
|
fill: '#673AB7',
|
||||||
|
stroke: {
|
||||||
|
normal: '#EDC6FB'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
code: {
|
||||||
|
activation: `
|
||||||
|
const state = context.getProperty('value')
|
||||||
|
const bits = context.getProperty('output bits')
|
||||||
|
const length = state.toString(2).length
|
||||||
|
const text = length > 10
|
||||||
|
? "0x" + context.printHex(state, Math.ceil(length/4))
|
||||||
|
: context.printBinary(state, length)
|
||||||
|
|
||||||
|
context.setBinary(0, state, bits === 0 ? length : bits)
|
||||||
|
context.innerText(text)
|
||||||
|
`
|
||||||
|
},
|
||||||
|
pins: {
|
||||||
|
inputs: {
|
||||||
|
count: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
integration: {
|
||||||
|
input: true
|
||||||
|
},
|
||||||
|
info: [],
|
||||||
|
properties: {
|
||||||
|
enabled: true,
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
base: 0,
|
||||||
|
name: 'output bits',
|
||||||
|
description: '(0 for auto)',
|
||||||
|
type: 'number',
|
||||||
|
needsUpdate: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
base: 0,
|
||||||
|
name: 'value',
|
||||||
|
type: 'number',
|
||||||
|
needsUpdate: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
category: categories.io
|
||||||
|
}
|
||||||
|
|
||||||
|
export default constTemplate
|
|
@ -9,12 +9,7 @@ import {
|
||||||
import { idStore } from '../stores/idStore'
|
import { idStore } from '../stores/idStore'
|
||||||
import { Context, InitialisationContext } from '../../activation/types/Context'
|
import { Context, InitialisationContext } from '../../activation/types/Context'
|
||||||
import { toFunction } from '../../activation/helpers/toFunction'
|
import { toFunction } from '../../activation/helpers/toFunction'
|
||||||
import {
|
import { Subscription, BehaviorSubject } from 'rxjs'
|
||||||
Subscription,
|
|
||||||
BehaviorSubject,
|
|
||||||
asapScheduler,
|
|
||||||
animationFrameScheduler
|
|
||||||
} from 'rxjs'
|
|
||||||
import { SimulationError } from '../../errors/classes/SimulationError'
|
import { SimulationError } from '../../errors/classes/SimulationError'
|
||||||
import { getGateTimePipes } from '../helpers/getGateTimePipes'
|
import { getGateTimePipes } from '../helpers/getGateTimePipes'
|
||||||
import { ImageStore } from '../../simulationRenderer/stores/imageStore'
|
import { ImageStore } from '../../simulationRenderer/stores/imageStore'
|
||||||
|
@ -25,7 +20,6 @@ import { saveStore } from '../../saving/stores/saveStore'
|
||||||
import { Wire } from './Wire'
|
import { Wire } from './Wire'
|
||||||
import { cleanSimulation } from '../../simulation-actions/helpers/clean'
|
import { cleanSimulation } from '../../simulation-actions/helpers/clean'
|
||||||
import { ExecutionQueue } from '../../activation/classes/ExecutionQueue'
|
import { ExecutionQueue } from '../../activation/classes/ExecutionQueue'
|
||||||
import { tap, observeOn } from 'rxjs/operators'
|
|
||||||
import { PropsSave } from '../../saving/types/SimulationSave'
|
import { PropsSave } from '../../saving/types/SimulationSave'
|
||||||
import { ValueOf } from '../../../common/lang/record/types/ValueOf'
|
import { ValueOf } from '../../../common/lang/record/types/ValueOf'
|
||||||
|
|
||||||
|
@ -139,7 +133,7 @@ export class Gate {
|
||||||
* Holds all the gate-related text
|
* Holds all the gate-related text
|
||||||
*/
|
*/
|
||||||
public text = {
|
public text = {
|
||||||
inner: new BehaviorSubject('text goes here')
|
inner: new BehaviorSubject<string | null>(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -170,21 +164,10 @@ export class Gate {
|
||||||
'context'
|
'context'
|
||||||
)
|
)
|
||||||
|
|
||||||
this.functions.onClick = toFunction(
|
this.functions.onClick = toFunction(this.template.code.onClick, 'context')
|
||||||
this.template.code.onClick,
|
|
||||||
'context'
|
|
||||||
)
|
|
||||||
|
|
||||||
this._pins.inputs = Gate.generatePins(
|
this._pins.inputs = Gate.generatePins(this.template.pins.inputs, 1, this)
|
||||||
this.template.pins.inputs,
|
this._pins.outputs = Gate.generatePins(this.template.pins.outputs, 2, this)
|
||||||
1,
|
|
||||||
this
|
|
||||||
)
|
|
||||||
this._pins.outputs = Gate.generatePins(
|
|
||||||
this.template.pins.outputs,
|
|
||||||
2,
|
|
||||||
this
|
|
||||||
)
|
|
||||||
|
|
||||||
if (this.template.material.type === 'image') {
|
if (this.template.material.type === 'image') {
|
||||||
ImageStore.set(this.template.material.fill)
|
ImageStore.set(this.template.material.fill)
|
||||||
|
@ -198,7 +181,7 @@ export class Gate {
|
||||||
const subscription = pin.state.pipe(...pipes).subscribe(() => {
|
const subscription = pin.state.pipe(...pipes).subscribe(() => {
|
||||||
if (this.template.code.async) {
|
if (this.template.code.async) {
|
||||||
this.executionQueue.push(async () => {
|
this.executionQueue.push(async () => {
|
||||||
return await this.update()
|
return this.update()
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
this.update()
|
this.update()
|
||||||
|
@ -305,7 +288,7 @@ export class Gate {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assign the props passed to the gate and mere them with the base ones
|
* Assign the props passed to the gate and merge them with the base ones
|
||||||
*/
|
*/
|
||||||
private assignProps(
|
private assignProps(
|
||||||
source: PropsSave,
|
source: PropsSave,
|
||||||
|
@ -313,14 +296,15 @@ export class Gate {
|
||||||
target: GateProps = this.props,
|
target: GateProps = this.props,
|
||||||
path: string[] = []
|
path: string[] = []
|
||||||
) {
|
) {
|
||||||
let shouldUpdate = false
|
// We don't want to update until every prop has been created
|
||||||
|
let lockUpdates = true
|
||||||
|
|
||||||
if (this.template.properties.enabled) {
|
if (this.template.properties.enabled) {
|
||||||
for (const prop of props) {
|
for (const prop of props) {
|
||||||
if (isGroup(prop)) {
|
if (isGroup(prop)) {
|
||||||
const { groupName } = prop
|
const { groupName } = prop
|
||||||
target[groupName] = {} as GateProps
|
target[groupName] = {} as GateProps
|
||||||
const needsUpdate = this.assignProps(
|
this.assignProps(
|
||||||
typeof source[groupName] === 'object'
|
typeof source[groupName] === 'object'
|
||||||
? (source[groupName] as PropsSave)
|
? (source[groupName] as PropsSave)
|
||||||
: {},
|
: {},
|
||||||
|
@ -329,10 +313,6 @@ export class Gate {
|
||||||
[...path, groupName]
|
[...path, groupName]
|
||||||
)
|
)
|
||||||
|
|
||||||
if (needsUpdate) {
|
|
||||||
shouldUpdate = true
|
|
||||||
}
|
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,7 +326,7 @@ export class Gate {
|
||||||
|
|
||||||
this.subscriptions.push(
|
this.subscriptions.push(
|
||||||
subject.subscribe((value) => {
|
subject.subscribe((value) => {
|
||||||
if (needsUpdate && path.length === 0) {
|
if (!lockUpdates && needsUpdate && path.length === 0) {
|
||||||
return this.update()
|
return this.update()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -357,14 +337,11 @@ export class Gate {
|
||||||
this.updateNestedProp([...path, name], value)
|
this.updateNestedProp([...path, name], value)
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
if (needsUpdate) {
|
|
||||||
shouldUpdate = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return shouldUpdate
|
lockUpdates = false
|
||||||
|
this.update()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -446,7 +423,8 @@ export class Gate {
|
||||||
|
|
||||||
const toLength = (
|
const toLength = (
|
||||||
original: string | number,
|
original: string | number,
|
||||||
length: number = maxLength
|
length: number = maxLength,
|
||||||
|
paddingChar = '0'
|
||||||
) => {
|
) => {
|
||||||
const value = original.toString(2)
|
const value = original.toString(2)
|
||||||
|
|
||||||
|
@ -455,31 +433,37 @@ export class Gate {
|
||||||
} else if (value.length > length) {
|
} else if (value.length > length) {
|
||||||
const difference = value.length - length
|
const difference = value.length - length
|
||||||
|
|
||||||
return value.substr(difference)
|
return value.slice(difference)
|
||||||
} else {
|
} else {
|
||||||
return `${'0'.repeat(length - value.length)}${value}`
|
return `${paddingChar.repeat(length - value.length)}${value}`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
printBinary: (value: number, bits: number = maxLength) =>
|
||||||
|
toLength(value.toString(2), bits),
|
||||||
|
printHex: (value: number, bits: number = maxLength) =>
|
||||||
|
toLength(value.toString(16), bits),
|
||||||
get: (index: number) => {
|
get: (index: number) => {
|
||||||
return this._pins.inputs[index].state.value
|
return this._pins.inputs[index].state.value
|
||||||
},
|
},
|
||||||
set: (index: number, state) => {
|
set: (index: number, state) => {
|
||||||
return this._pins.outputs[index].state.next(state)
|
return this._pins.outputs[index].state.next(state)
|
||||||
},
|
},
|
||||||
|
getOutput: (index: number) => {
|
||||||
|
return this._pins.outputs[index].state.value
|
||||||
|
},
|
||||||
getBinary: (index: number) => {
|
getBinary: (index: number) => {
|
||||||
return parseInt(this._pins.inputs[index].state.value, 2)
|
return parseInt(this._pins.inputs[index].state.value, 2)
|
||||||
},
|
},
|
||||||
setBinary: (
|
setBinary: (index: number, value: number, bits: number = maxLength) => {
|
||||||
index: number,
|
|
||||||
value: number,
|
|
||||||
bits: number = maxLength
|
|
||||||
) => {
|
|
||||||
return this._pins.outputs[index].state.next(
|
return this._pins.outputs[index].state.next(
|
||||||
toLength(value.toString(2), bits)
|
toLength(value.toString(2), bits)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
getOutputBinary: (index: number) => {
|
||||||
|
return parseInt(this._pins.outputs[index].state.value, 2)
|
||||||
|
},
|
||||||
invertBinary: (value: number) => {
|
invertBinary: (value: number) => {
|
||||||
return value ^ ((1 << maxLength) - 1)
|
return value ^ ((1 << maxLength) - 1)
|
||||||
},
|
},
|
||||||
|
@ -489,7 +473,16 @@ export class Gate {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getProperty: (name: string) => {
|
getProperty: (name: string) => {
|
||||||
|
if (this.props[name] === undefined) {
|
||||||
|
throw new Error(
|
||||||
|
[
|
||||||
|
`Cannot find property ${name} on gate ${this.template.metadata.name}.`,
|
||||||
|
`Current values: ${Object.keys(this.props)}`
|
||||||
|
].join('\n')
|
||||||
|
)
|
||||||
|
} else {
|
||||||
return this.props[name].value
|
return this.props[name].value
|
||||||
|
}
|
||||||
},
|
},
|
||||||
setProperty: (name: string, value: string | number | boolean) => {
|
setProperty: (name: string, value: string | number | boolean) => {
|
||||||
const subject = this.props[name]
|
const subject = this.props[name]
|
||||||
|
@ -551,6 +544,6 @@ export class Gate {
|
||||||
private static generatePins(options: PinCount, type: number, gate: Gate) {
|
private static generatePins(options: PinCount, type: number, gate: Gate) {
|
||||||
return [...Array(options.count)]
|
return [...Array(options.count)]
|
||||||
.fill(true)
|
.fill(true)
|
||||||
.map((v, index) => new Pin(type, gate))
|
.map((_v, _index) => new Pin(type, gate))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ export type RawProp<
|
||||||
type: 'number' | 'string' | 'text' | 'boolean'
|
type: 'number' | 'string' | 'text' | 'boolean'
|
||||||
base: T
|
base: T
|
||||||
name: string
|
name: string
|
||||||
|
description?: string
|
||||||
needsUpdate?: boolean
|
needsUpdate?: boolean
|
||||||
}
|
}
|
||||||
export type Property<
|
export type Property<
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
export const textSettings = {
|
export const textSettings = {
|
||||||
font: '30px Roboto',
|
font: '30px monospace',
|
||||||
offset: 35,
|
offset: 35,
|
||||||
fill: `rgba(256,256,256,0.75)`
|
fill: `rgba(256,256,256,0.75)`
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ export const pinFill = (renderer: SimulationRenderer, pin: Pin) => {
|
||||||
.map((key) =>
|
.map((key) =>
|
||||||
chunked
|
chunked
|
||||||
.flat()
|
.flat()
|
||||||
.filter((v, index) => index % 3 === key)
|
.filter((_v, index) => index % 3 === key)
|
||||||
.reduce((acc, curr) => acc + curr, 0)
|
.reduce((acc, curr) => acc + curr, 0)
|
||||||
)
|
)
|
||||||
.map((value) => Math.floor(value / digits.length))
|
.map((value) => Math.floor(value / digits.length))
|
||||||
|
|
|
@ -61,6 +61,7 @@ export const renderGate = (
|
||||||
ctx.stroke()
|
ctx.stroke()
|
||||||
|
|
||||||
if (gate.template.tags.includes('integrated')) {
|
if (gate.template.tags.includes('integrated')) {
|
||||||
|
ctx.textBaseline = 'top'
|
||||||
ctx.fillStyle = textSettings.fill
|
ctx.fillStyle = textSettings.fill
|
||||||
ctx.fillText(
|
ctx.fillText(
|
||||||
gate.template.metadata.name,
|
gate.template.metadata.name,
|
||||||
|
@ -69,5 +70,25 @@ export const renderGate = (
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const text = gate.text.inner.value
|
||||||
|
if (text !== null) {
|
||||||
|
ctx.textBaseline = 'middle'
|
||||||
|
ctx.fillStyle = textSettings.fill
|
||||||
|
|
||||||
|
let size = 30
|
||||||
|
if (text.length >= 8) {
|
||||||
|
size = 15
|
||||||
|
} else if (text.length >= 6) {
|
||||||
|
size = 20
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.font = `${size}px monospace`
|
||||||
|
ctx.fillText(
|
||||||
|
text,
|
||||||
|
relativeTransform.center[0],
|
||||||
|
relativeTransform.center[1] + 2
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
ctx.restore()
|
ctx.restore()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue