multi bit math

This commit is contained in:
Matei Adriel 2019-07-31 18:28:27 +03:00
parent 0251dd52d9
commit 12db01963f
36 changed files with 353 additions and 60 deletions

7
src/assets/4decoder.svg Normal file
View file

@ -0,0 +1,7 @@
<svg width="800" height="800" viewBox="0 0 800 800" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M800 0H0V800H800V0Z" fill="#DB00FF"/>
<path d="M386.932 308H517L448.214 400L517 492H386.932C386.932 492 306.265 492 305.014 400C303.763 308 386.932 308 386.932 308Z" stroke="white" stroke-width="10"/>
<path d="M555.089 435.379H477M555.089 365.621H477H555.089ZM572 333H493.911H572ZM572 468H493.911H572Z" stroke="white" stroke-width="10"/>
<path d="M555.089 435.379H477M555.089 365.621H477H555.089ZM572 333H493.911H572ZM572 468H493.911H572Z" stroke="white" stroke-width="10"/>
<path d="M555 435.379H476.5M306.5 396.234H228H306.5ZM572 333H493.5H572ZM572 468H493.5H572Z" stroke="white" stroke-width="10"/>
</svg>

After

Width:  |  Height:  |  Size: 718 B

7
src/assets/4encoder.svg Normal file
View file

@ -0,0 +1,7 @@
<svg width="800" height="800" viewBox="0 0 800 800" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="800" height="800" fill="#DB00FF"/>
<path d="M424.682 308H294L363.11 400L294 492H424.682C424.682 492 505.729 492 506.986 400C508.243 308 424.682 308 424.682 308Z" stroke="white" stroke-width="10"/>
<path d="M256 365.5H334.5M239 333H317.5M239 467.5H317.5M256 435H334.5" stroke="white" stroke-width="10"/>
<path d="M256 365.5H334.5M239 333H317.5M239 467.5H317.5M256 435H334.5" stroke="white" stroke-width="10"/>
<path d="M504.5 396H583M239 333H317.5M239 467.5H317.5M256 435H334.5" stroke="white" stroke-width="10"/>
</svg>

After

Width:  |  Height:  |  Size: 633 B

View file

@ -1,18 +1,22 @@
import { Simulation, SimulationEnv } from '../../simulation/classes/Simulation' import { Simulation, SimulationEnv } from '../../simulation/classes/Simulation'
import { SimulationError } from '../../errors/classes/SimulationError' import { PinState } from '../../simulation/classes/Pin'
import { fromSimulationState } from '../../saving/helpers/fromState'
export interface Context { export interface Context {
memory: Record<string, unknown>
getProperty: (name: string) => unknown getProperty: (name: string) => unknown
setProperty: (name: string, value: unknown) => void setProperty: (name: string, value: unknown) => void
get: (index: number) => boolean get: (index: number) => PinState
set: (index: number, state: boolean) => void set: (index: number, state: PinState) => void
getBinary: (index: number) => number
setBinary: (index: number, value: number, bits: number) => void
invertBinary: (value: number) => number
color: (color: string) => void color: (color: string) => void
innerText: (value: string) => void innerText: (value: string) => void
update: () => void update: () => void
toLength: (value: number | PinState, length: number) => string
maxLength: number
enviroment: SimulationEnv enviroment: SimulationEnv
colors: Record<string, string> colors: Record<string, string>
memory: Record<string, unknown>
} }
export interface InitialisationContext { export interface InitialisationContext {

View file

@ -0,0 +1,30 @@
/**
* Gets the 3 chunks frmo a hex color string
*
* @param color The color string
*/
export const fromHexColorString = (color: string) => {
const actual = color.slice(1)
const chunks = [
actual.substr(0, 2),
actual.substr(2, 2),
actual.substr(4, 2)
]
const numbers = chunks.map(chunk => parseInt(chunk, 16))
return numbers
}
/**
* Rebuilds a color from its chunks
*/
export const fromChunks = (chunks: number[]) => {
return `#${chunks.reduce((acc, curr) => {
const stringified = curr.toString(16)
return (
acc + (stringified.length === 1 ? `0${stringified}` : stringified)
)
}, '')}`
}

View file

@ -19,6 +19,7 @@ const LogicGatePage = () => {
<div className="gate-grid"> <div className="gate-grid">
{gates {gates
.map(getTemplateSafely) .map(getTemplateSafely)
.sort((a, b) => a.category - b.category)
.filter(template => { .filter(template => {
return ( return (
renderer.simulation.mode === 'project' || renderer.simulation.mode === 'project' ||

View file

@ -14,6 +14,8 @@ import xnorTemplate from './templates/xnor'
import xorTemplate from './templates/xor' import xorTemplate from './templates/xor'
import halfAdderTemplate from './templates/halfAdder' import halfAdderTemplate from './templates/halfAdder'
import fullAdderTemplate from './templates/fullAdder' import fullAdderTemplate from './templates/fullAdder'
import _4bitEncoderTemplate from './templates/4bitEncoder'
import _4bitDecoderTemplate from './templates/4bitDecoder'
export const defaultSimulationName = 'default' export const defaultSimulationName = 'default'
export const baseTemplates: DeepPartial<GateTemplate>[] = [ export const baseTemplates: DeepPartial<GateTemplate>[] = [
@ -30,7 +32,9 @@ export const baseTemplates: DeepPartial<GateTemplate>[] = [
xnorTemplate, xnorTemplate,
xorTemplate, xorTemplate,
halfAdderTemplate, halfAdderTemplate,
fullAdderTemplate fullAdderTemplate,
_4bitEncoderTemplate,
_4bitDecoderTemplate
// commentTemplate // commentTemplate
] ]

View file

@ -0,0 +1,4 @@
/**
* The actual scale for the 4-bit encoder / decoder
*/
export const _4BitScale = [150, 150]

View file

@ -0,0 +1,8 @@
export const categories = {
basic: 0,
io: 3,
math: 1,
time: 2,
advancedIo: 4,
compressing: 5
}

View file

@ -0,0 +1,10 @@
export const adderActivation = (full: boolean) => `
const a = context.getBinary(0)
const b = context.getBinary(1)
${full ? `const c = context.getBinary(2)` : ''}
const sum = a + b + ${full ? `c` : '0'}
context.setBinary(0, sum)
context.setBinary(1, sum >> context.maxLength)
`

View file

@ -9,6 +9,10 @@ import { Camera } from '../../simulationRenderer/classes/Camera'
import { Simulation, SimulationEnv } from '../../simulation/classes/Simulation' import { Simulation, SimulationEnv } from '../../simulation/classes/Simulation'
import { Wire } from '../../simulation/classes/Wire' import { Wire } from '../../simulation/classes/Wire'
import { templateStore } from '../stores/templateStore' import { templateStore } from '../stores/templateStore'
import { calculateGateHeight } from '../../simulationRenderer/helpers/calculateGateHeight'
import { getRendererSafely } from '../../logic-gates/helpers/getRendererSafely'
import { rendererSubject } from '../../core/subjects/rendererSubject'
import { filter, take } from 'rxjs/operators'
/** /**
* Contains methods for transforming saved state into the respective class instances * Contains methods for transforming saved state into the respective class instances
@ -38,9 +42,33 @@ export const fromSimulationState = (
gateState.id, gateState.id,
gateState.props gateState.props
) )
gate.transform = fromTransformState(gateState.transform) gate.transform = fromTransformState(gateState.transform)
simulation.push(gate) const fixWrongHeight = () => {
gate.transform.height = calculateGateHeight(
getRendererSafely(),
gate
)
}
try {
fixWrongHeight()
} catch {
// retry if an error occured
rendererSubject
.pipe(
filter(x => !!x),
take(1)
)
.subscribe(() => {
if (gate) {
fixWrongHeight()
}
})
} finally {
simulation.push(gate)
}
} }
for (const wireState of state.wires) { for (const wireState of state.wires) {

View file

@ -0,0 +1,40 @@
import { PartialTemplate } from '../types/PartialTemplate'
import { categories } from '../data/categories'
import { _4BitScale } from '../data/4BitScale'
/**
* The template of the _4bitDecoder gate
*/
const _4bitDecoderTemplate: PartialTemplate = {
metadata: {
name: `4 bit decoder`
},
category: categories.compressing,
code: {
activation: `
const input = context.get(0)
const set = (index) => {
context.set(3 - index, input[index] || '0')
}
for (const index of [0,1,2,3]){
set(index)
}
`
},
material: {
type: 'image',
fill: require('../../../assets/4decoder')
},
shape: {
scale: _4BitScale
},
pins: {
outputs: {
count: 4
}
}
}
export default _4bitDecoderTemplate

View file

@ -0,0 +1,39 @@
import { PartialTemplate } from '../types/PartialTemplate'
import { categories } from '../data/categories'
import { _4BitScale } from '../data/4BitScale'
/**
* The template of the _4bitEncoder gate
*/
const _4bitEncoderTemplate: PartialTemplate = {
metadata: {
name: `4 bit encoder`
},
category: categories.compressing,
code: {
activation: `
const get = (num) => {
const value = context.get(num)
return value[value.length - 1]
}
const total = get(3) + get(2) + get(1) + get(0)
context.set(0, total)
`
},
material: {
type: 'image',
fill: require('../../../assets/4encoder')
},
shape: {
scale: _4BitScale
},
pins: {
inputs: {
count: 4
}
}
}
export default _4bitEncoderTemplate

View file

@ -12,7 +12,12 @@ const andTemplate: PartialTemplate = {
fill: require('../../../assets/and') fill: require('../../../assets/and')
}, },
code: { code: {
activation: `context.set(0, context.get(0) && context.get(1))` activation: `
const a = context.getBinary(0)
const b = context.getBinary(1)
const c = a & b
context.setBinary(0, c)`
}, },
pins: { pins: {
inputs: { inputs: {

View file

@ -1,4 +1,5 @@
import { PartialTemplate } from '../types/PartialTemplate' import { PartialTemplate } from '../types/PartialTemplate'
import { categories } from '../data/categories'
/** /**
* The template of the button gate * The template of the button gate
@ -27,7 +28,7 @@ const buttonTemplate: PartialTemplate = {
activation: ` activation: `
const state = context.getProperty('active') const state = context.getProperty('active')
context.set(0, state) context.set(0, Number(state).toString(2))
context.color(!state ? context.colors.main : context.colors.pressed) context.color(!state ? context.colors.main : context.colors.pressed)
` `
}, },
@ -50,7 +51,8 @@ const buttonTemplate: PartialTemplate = {
needsUpdate: true needsUpdate: true
} }
] ]
} },
category: categories.io
} }
export default buttonTemplate export default buttonTemplate

View file

@ -1,4 +1,6 @@
import { PartialTemplate } from '../types/PartialTemplate' import { PartialTemplate } from '../types/PartialTemplate'
import { categories } from '../data/categories'
import { adderActivation } from '../helpers/adderActivation'
/** /**
* The template of the fullAdder gate * The template of the fullAdder gate
@ -12,12 +14,7 @@ const fullAdderTemplate: PartialTemplate = {
fill: require('../../../assets/full-adder') fill: require('../../../assets/full-adder')
}, },
code: { code: {
activation: ` activation: adderActivation(true)
const result = context.get(0) + context.get(1) + context.get(2)
context.set(0, result & 1)
context.set(1, result >> 1)
`
}, },
pins: { pins: {
inputs: { inputs: {
@ -26,7 +23,8 @@ const fullAdderTemplate: PartialTemplate = {
outputs: { outputs: {
count: 2 count: 2
} }
} },
category: categories.math
} }
export default fullAdderTemplate export default fullAdderTemplate

View file

@ -1,4 +1,6 @@
import { PartialTemplate } from '../types/PartialTemplate' import { PartialTemplate } from '../types/PartialTemplate'
import { categories } from '../data/categories'
import { adderActivation } from '../helpers/adderActivation'
/** /**
* The template of the halfAdder gate * The template of the halfAdder gate
@ -12,12 +14,7 @@ const halfAdderTemplate: PartialTemplate = {
fill: require('../../../assets/half-adder') fill: require('../../../assets/half-adder')
}, },
code: { code: {
activation: ` activation: adderActivation(false)
const result = context.get(0) + context.get(1)
context.set(0, result & 1)
context.set(1, result >> 1)
`
}, },
pins: { pins: {
inputs: { inputs: {
@ -26,7 +23,8 @@ const halfAdderTemplate: PartialTemplate = {
outputs: { outputs: {
count: 2 count: 2
} }
} },
category: categories.math
} }
export default halfAdderTemplate export default halfAdderTemplate

View file

@ -1,4 +1,5 @@
import { PartialTemplate } from '../types/PartialTemplate' import { PartialTemplate } from '../types/PartialTemplate'
import { categories } from '../data/categories'
/** /**
* The template of the light gate * The template of the light gate
@ -23,7 +24,7 @@ const lightTemplate: PartialTemplate = {
activation: ` activation: `
const { main, active } = context.colors const { main, active } = context.colors
context.color(context.get(0) ? active : main) context.color(parseInt(context.get(0),2) ? active : main)
` `
}, },
integration: { integration: {
@ -34,7 +35,8 @@ const lightTemplate: PartialTemplate = {
outputs: { outputs: {
count: 0 count: 0
} }
} },
category: categories.io
} }
export default lightTemplate export default lightTemplate

View file

@ -12,7 +12,12 @@ const nandTemplate: PartialTemplate = {
fill: require('../../../assets/nand') fill: require('../../../assets/nand')
}, },
code: { code: {
activation: `context.set(0, !context.get(0) || !context.get(1))` activation: `
const a = context.getBinary(0)
const b = context.getBinary(1)
const c = context.invertBinary(a & b)
context.setBinary(0, c)`
}, },
pins: { pins: {
inputs: { inputs: {

View file

@ -12,7 +12,13 @@ const norTemplate: PartialTemplate = {
fill: require('../../../assets/nor') fill: require('../../../assets/nor')
}, },
code: { code: {
activation: `context.set(0, !(context.get(0) || context.get(1)))` activation: `
const a = context.getBinary(0)
const b = context.getBinary(1)
const c = context.invertBinary(a | b)
context.setBinary(0, c)
`
}, },
pins: { pins: {
inputs: { inputs: {

View file

@ -12,7 +12,13 @@ const notTemplate: PartialTemplate = {
fill: require('../../../assets/not') fill: require('../../../assets/not')
}, },
code: { code: {
activation: `context.set(0, !context.get(0))` activation: `
context.setBinary(0,
context.invertBinary(
context.getBinary(0)
)
)
`
}, },
info: ['https://en.wikipedia.org/wiki/Inverter_(logic_gate)'] info: ['https://en.wikipedia.org/wiki/Inverter_(logic_gate)']
} }

View file

@ -12,7 +12,12 @@ const orTemplate: PartialTemplate = {
fill: require('../../../assets/or') fill: require('../../../assets/or')
}, },
code: { code: {
activation: `context.set(0, context.get(0) || context.get(1))` activation: `
const a = context.getBinary(0)
const b = context.getBinary(1)
context.setBinary(0, a | b)
`
}, },
pins: { pins: {
inputs: { inputs: {

View file

@ -1,5 +1,6 @@
import { PartialTemplate } from '../types/PartialTemplate' import { PartialTemplate } from '../types/PartialTemplate'
import { delayProperties } from '../data/delayProperties' import { delayProperties } from '../data/delayProperties'
import { categories } from '../data/categories'
/** /**
* The template of the parallelDelayer gate * The template of the parallelDelayer gate
@ -24,7 +25,8 @@ const parallelDelayerTemplate: PartialTemplate = {
}) })
` `
}, },
properties: delayProperties properties: delayProperties,
category: categories.time
} }
export default parallelDelayerTemplate export default parallelDelayerTemplate

View file

@ -1,4 +1,5 @@
import { PartialTemplate } from '../types/PartialTemplate' import { PartialTemplate } from '../types/PartialTemplate'
import { categories } from '../data/categories'
/** /**
* The template of the rgbLight gate * The template of the rgbLight gate
@ -43,7 +44,8 @@ const rgbLightTemplate: PartialTemplate = {
inputs: { inputs: {
count: 3 count: 3
} }
} },
category: categories.advancedIo
} }
export default rgbLightTemplate export default rgbLightTemplate

View file

@ -1,5 +1,6 @@
import { PartialTemplate } from '../types/PartialTemplate' import { PartialTemplate } from '../types/PartialTemplate'
import { delayProperties } from '../data/delayProperties' import { delayProperties } from '../data/delayProperties'
import { categories } from '../data/categories'
/** /**
* The template of the sequentialDelayer gate * The template of the sequentialDelayer gate
@ -25,7 +26,8 @@ const sequentialDelayerTemplate: PartialTemplate = {
`, `,
async: true async: true
}, },
properties: delayProperties properties: delayProperties,
category: categories.time
} }
export default sequentialDelayerTemplate export default sequentialDelayerTemplate

View file

@ -13,11 +13,11 @@ const xnorTemplate: PartialTemplate = {
}, },
code: { code: {
activation: ` activation: `
const a = context.get(0) const a = context.getBinary(0)
const b = context.get(1) const b = context.getBinary(1)
const c = (a && b) || !(a || b) const c = context.invertBinary(a ^ b)
context.set(0, c)` context.setBinary(0, c)`
}, },
info: ['https://en.wikipedia.org/wiki/XNOR_gate'], info: ['https://en.wikipedia.org/wiki/XNOR_gate'],
pins: { pins: {

View file

@ -13,11 +13,10 @@ const xorTemplate: PartialTemplate = {
}, },
code: { code: {
activation: ` activation: `
const a = context.get(0) const a = context.getBinary(0)
const b = context.get(1) const b = context.getBinary(1)
const c = (a || b) && (!a || !b)
context.setBinary(0, a ^ b)`
context.set(0, c)`
}, },
info: ['https://en.wikipedia.org/wiki/XOR_gate'], info: ['https://en.wikipedia.org/wiki/XOR_gate'],
pins: { pins: {

View file

@ -360,13 +360,49 @@ export class Gate {
* Generates the activation context * Generates the activation context
*/ */
public getContext(): Context { public getContext(): Context {
const maxLength = Math.max(
...this._pins.inputs.map(pin => pin.state.value.length)
)
const toLength = (
original: string | number,
length: number = maxLength
) => {
const value = original.toString(2)
if (value.length === length) {
return value
} else if (value.length > length) {
const difference = value.length - length
return value.substr(difference)
} else {
return `${'0'.repeat(length - value.length)}${value}`
}
}
return { return {
get: (index: number) => { get: (index: number) => {
return this._pins.inputs[index].state.value return this._pins.inputs[index].state.value
}, },
set: (index: number, state: boolean = false) => { set: (index: number, state) => {
return this._pins.outputs[index].state.next(state) return this._pins.outputs[index].state.next(state)
}, },
getBinary: (index: number) => {
return parseInt(this._pins.inputs[index].state.value, 2)
},
setBinary: (
index: number,
value: number,
bits: number = maxLength
) => {
return this._pins.outputs[index].state.next(
toLength(value.toString(2), bits)
)
},
invertBinary: (value: number) => {
return value ^ ((1 << maxLength) - 1)
},
color: (color: string) => { color: (color: string) => {
if (this.template.material.type === 'color') { if (this.template.material.type === 'color') {
this.template.material.fill = color this.template.material.fill = color
@ -384,6 +420,8 @@ export class Gate {
update: () => { update: () => {
this.update() this.update()
}, },
toLength,
maxLength,
enviroment: this.env, enviroment: this.env,
memory: this.memory, memory: this.memory,
colors: { colors: {
@ -430,6 +468,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(() => new Pin(type, gate)) .map((v, index) => new Pin(type, gate))
} }
} }

View file

@ -2,6 +2,8 @@ import { SubscriptionData } from '../types/SubscriptionData'
import { BehaviorSubject } from 'rxjs' import { BehaviorSubject } from 'rxjs'
import { Gate } from './Gate' import { Gate } from './Gate'
export type PinState = string
/* Types: /* Types:
First bit = input First bit = input
@ -9,7 +11,7 @@ Second bit = output
*/ */
export class Pin { export class Pin {
public state = new BehaviorSubject(false) public state = new BehaviorSubject<PinState>('0')
public pairs = new Set<Pin>() public pairs = new Set<Pin>()
private subscriptions: SubscriptionData<Pin>[] = [] private subscriptions: SubscriptionData<Pin>[] = []

View file

@ -1,4 +1,5 @@
import { GateTemplate } from './types/GateTemplate' import { GateTemplate } from './types/GateTemplate'
import { categories } from '../saving/data/categories'
export const DefaultGateTemplate: GateTemplate = { export const DefaultGateTemplate: GateTemplate = {
metadata: { metadata: {
@ -57,5 +58,6 @@ export const DefaultGateTemplate: GateTemplate = {
innerText: { innerText: {
enabled: false, enabled: false,
color: 'white' color: 'white'
} },
category: categories.basic
} }

View file

@ -10,6 +10,7 @@ import { toast } from 'react-toastify'
import { createToastArguments } from '../../toasts/helpers/createToastArguments' import { createToastArguments } from '../../toasts/helpers/createToastArguments'
import { CurrentLanguage } from '../../internalisation/stores/currentLanguage' import { CurrentLanguage } from '../../internalisation/stores/currentLanguage'
import { GateInitter } from '../../simulationRenderer/types/GateInitter' import { GateInitter } from '../../simulationRenderer/types/GateInitter'
import { calculateGateHeight } from '../../simulationRenderer/helpers/calculateGateHeight'
/** /**
* Adds a gate to a renderer * Adds a gate to a renderer
@ -43,6 +44,7 @@ export const addGate = (
const offset = multiply([scalarOffset, scalarOffset], renderer.spawnCount) const offset = multiply([scalarOffset, scalarOffset], renderer.spawnCount)
gate.transform.position = add(origin, offset) gate.transform.position = add(origin, offset)
gate.transform.height = calculateGateHeight(renderer, gate)
renderer.simulation.push(gate) renderer.simulation.push(gate)
renderer.spawnCount++ renderer.spawnCount++

View file

@ -2,7 +2,7 @@ import { GateTemplate } from '../types/GateTemplate'
import { debounceTime, throttleTime } from 'rxjs/operators' import { debounceTime, throttleTime } from 'rxjs/operators'
import { MonoTypeOperatorFunction, pipe } from 'rxjs' import { MonoTypeOperatorFunction, pipe } from 'rxjs'
export type TimePipe = MonoTypeOperatorFunction<boolean> export type TimePipe = MonoTypeOperatorFunction<string>
export const getGateTimePipes = (template: GateTemplate) => { export const getGateTimePipes = (template: GateTemplate) => {
const pipes: TimePipe[] = [] const pipes: TimePipe[] = []

View file

@ -79,4 +79,5 @@ export interface GateTemplate {
color: string color: string
enabled: boolean enabled: boolean
} }
category: number // for better sorting
} }

View file

@ -13,8 +13,8 @@ export const defaultSimulationRendererOptions: SimulationRendererOptions = {
pinStrokeColor: '#888888', pinStrokeColor: '#888888',
pinStrokeWidth: 3, pinStrokeWidth: 3,
pinFill: { pinFill: {
open: 'rgb(255,216,20)', open: '#ffff22',
closed: 'rgb(90,90,90)' closed: '#555555'
}, },
gateStroke: { gateStroke: {
active: 'yellow', active: 'yellow',

View file

@ -0,0 +1,20 @@
import { Gate } from '../../simulation/classes/Gate'
import { SimulationRenderer } from '../classes/SimulationRenderer'
/**
* Calculates the correct height for a gate
*
* @param renderer The renderer to get the pin-radius of
* @param gate The gate to get the height of
*/
export const calculateGateHeight = (
renderer: SimulationRenderer,
gate: Gate
) => {
return Math.max(
gate.transform.scale[1],
Math.max(gate._pins.outputs.length, gate._pins.inputs.length) *
4 *
renderer.options.gates.pinRadius
)
}

View file

@ -1,15 +1,29 @@
import { Pin } from '../../simulation/classes/Pin' import { Pin } from '../../simulation/classes/Pin'
import { SimulationRenderer } from '../classes/SimulationRenderer' import { SimulationRenderer } from '../classes/SimulationRenderer'
import { fromHexColorString, fromChunks } from '../../colors/helpers/fromHex'
export const pinFill = (renderer: SimulationRenderer, pin: Pin) => { export const pinFill = (renderer: SimulationRenderer, pin: Pin) => {
let color = 'rgba(0,0,0,0)' let color = 'rgba(0,0,0,0)'
if (pin.pairs.size) { if (pin.pairs.size) {
if (pin.state.value) { const { open, closed } = renderer.options.gates.pinFill
color = renderer.options.gates.pinFill.open const digits = Array.from(pin.state.value).map(Number)
} else {
color = renderer.options.gates.pinFill.closed const colors = digits.map(digit => (digit ? open : closed))
} const chunked = colors.map(fromHexColorString)
const summed = [0, 1, 2]
.map(key =>
chunked
.flat()
.filter((v, index) => index % 3 === key)
.reduce((acc, curr) => acc + curr, 0)
)
.map(value => Math.floor(value / digits.length))
color = fromChunks(summed)
// console.log(color)
} }
return color return color

View file

@ -32,12 +32,12 @@ export const renderGate = (
ctx.save() ctx.save()
const r = useTransform(ctx, gate.transform) const relativeTransform = useTransform(ctx, gate.transform)
const renderingParameters = [ const renderingParameters = [
r.x, relativeTransform.x,
r.y, relativeTransform.y,
r.width, relativeTransform.width,
r.height, relativeTransform.height,
gate.template.shape.rounded ? gate.template.shape.radius : 0 gate.template.shape.rounded ? gate.template.shape.radius : 0
] ]