summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Cully <bjc@kublai.com>2021-02-19 12:42:11 -0500
committerBrian Cully <bjc@kublai.com>2021-02-19 12:42:11 -0500
commit0a703e8f463dfadcf102e0b553d798b8046b03ee (patch)
tree791775233693855907d6bbc79c5c0846426c6611
parent555e3faea8d3cc8ae5764876fe957039cdc0d431 (diff)
downloadmolsim2-0a703e8f463dfadcf102e0b553d798b8046b03ee.tar.gz
molsim2-0a703e8f463dfadcf102e0b553d798b8046b03ee.zip
Add amino acid selection after mutation.
-rw-r--r--amino-acid-selector.mjs33
-rw-r--r--codon.mjs4
-rw-r--r--genome.mjs1
-rw-r--r--index.html27
-rw-r--r--main.mjs3
-rw-r--r--mobile.css47
-rw-r--r--rules.mjs77
7 files changed, 189 insertions, 3 deletions
diff --git a/amino-acid-selector.mjs b/amino-acid-selector.mjs
new file mode 100644
index 0000000..fe71098
--- /dev/null
+++ b/amino-acid-selector.mjs
@@ -0,0 +1,33 @@
+class AminoAcidSelector {
+ constructor(elt) {
+ this.elt = elt
+ for (const elt of this.elt.querySelectorAll('li')) {
+ elt.addEventListener('click', this.select.bind(this))
+ }
+ }
+
+ attach() {
+ this.elt.classList.remove('hidden')
+ }
+
+ detach() {
+ this.elt.classList.add('hidden')
+ }
+
+ get onItemSelected() {
+ if (this._onItemSelected !== undefined) {
+ return this._onItemSelected
+ }
+ return () => {}
+ }
+
+ set onItemSelected(fn) {
+ this._onItemSelected = fn
+ }
+
+ select(evt) {
+ this.onItemSelected(evt.currentTarget.innerText)
+ }
+}
+
+export default AminoAcidSelector
diff --git a/codon.mjs b/codon.mjs
index 612e4ac..6163883 100644
--- a/codon.mjs
+++ b/codon.mjs
@@ -25,6 +25,10 @@ class Codon {
return this._elt
}
+ get value() {
+ return this.bases.map(b => b.value).join('')
+ }
+
lock() {
this.bases.forEach(n => n.lock())
this.aminoAcid.lock()
diff --git a/genome.mjs b/genome.mjs
index 49cae0f..432a59b 100644
--- a/genome.mjs
+++ b/genome.mjs
@@ -81,6 +81,7 @@ class Genome {
for (const c of this.codons) {
for (const b of c.bases) {
if (b === this._selectedNucleotide) {
+ this.selectedCodon = c
this.onNucleotideSelectionChanged(this._selectedNucleotide, i)
return
}
diff --git a/index.html b/index.html
index cb6137f..0661091 100644
--- a/index.html
+++ b/index.html
@@ -103,6 +103,33 @@
<li>T</li>
</ul>
+ <div id='amino-acid-selector' class='hidden'>
+ <p>Select the amino acid for the codon <span class='codon'>--</span></p>
+ <ul>
+ <li>Ala</li>
+ <li>Arg</li>
+ <li>Asn</li>
+ <li>Asp</li>
+ <li>Cys</li>
+ <li>Gln</li>
+ <li>Glu</li>
+ <li>Gly</li>
+ <li>His</li>
+ <li>Ile</li>
+ <li>Leu</li>
+ <li>Lys</li>
+ <li>Met</li>
+ <li>Phe</li>
+ <li>Pro</li>
+ <li>Ser</li>
+ <li>Thr</li>
+ <li>Trp</li>
+ <li>Tyr</li>
+ <li>Val</li>
+ <li>STOP</li>
+ </ul>
+ </div>
+
<script src='main.mjs' type='module'></script>
</body>
</html>
diff --git a/main.mjs b/main.mjs
index aed3c1a..1af1c56 100644
--- a/main.mjs
+++ b/main.mjs
@@ -3,6 +3,7 @@ import Rules from './rules.mjs'
function init() {
const genomeList = document.querySelector('#genome-history')
const die = document.querySelector('#die')
+ const aminoAcidSelector = document.querySelector('#amino-acid-selector')
const nucleotideSelector = document.querySelector('#nucleotide-selector')
const instructions = document.querySelector('#instructions')
const cloneButton = document.querySelector('#clone')
@@ -10,7 +11,7 @@ function init() {
const printButton = document.querySelector('#print')
const errors = document.querySelector('#errors')
- const rules = new Rules(die, instructions, genomeList, nucleotideSelector, cloneButton, remainingIterations, printButton, errors)
+ const rules = new Rules(die, instructions, genomeList, aminoAcidSelector, nucleotideSelector, cloneButton, remainingIterations, printButton, errors)
}
init()
diff --git a/mobile.css b/mobile.css
index 0f7f87b..6d2d5a9 100644
--- a/mobile.css
+++ b/mobile.css
@@ -112,6 +112,53 @@ body {
background-color: orange;
}
+#amino-acid-selector {
+ position: fixed;
+ left: 50%;
+ top: 50%;
+ width: 50%;
+ transform: translate(-50%, -50%);
+
+ background-color: ivory;
+ border: 1px solid black;
+ cursor: pointer;
+}
+
+#amino-acid-selector p {
+ margin: 0;
+ padding: 10px;
+
+ border-bottom: 1px dashed black;
+}
+
+#amino-acid-selector .codon {
+ font-weight: bold;
+}
+
+#amino-acid-selector ul {
+ display: flex;
+ flex-wrap: wrap;
+
+ margin: 0;
+ padding: 10px;
+
+ list-style-type: none;
+ white-space: nowrap;
+}
+
+#amino-acid-selector li {
+ display: flex-inline;
+
+ height: 3ex;
+ width: 3em;
+
+ text-align: center;
+}
+
+#amino-acid-selector li:hover {
+ background-color: orange;
+}
+
.genome .nucleotide.selected,
.genome:not(.locked) .nucleotide.selected:hover {
background-color: red;
diff --git a/rules.mjs b/rules.mjs
index 8f038bc..58b794f 100644
--- a/rules.mjs
+++ b/rules.mjs
@@ -1,4 +1,6 @@
import { randomItem, ordinalSuffix } from './utils.mjs'
+import AminoAcid from './amino-acid.mjs'
+import AminoAcidSelector from './amino-acid-selector.mjs'
import Genome from './genome.mjs'
import Nucleotide from './nucleotide.mjs'
import Die from './die.mjs'
@@ -184,7 +186,67 @@ class PerformMutation {
return
}
- this.selectedNucleotide.value = base
+ this.rules.next(new SelectAminoAcid(this.rules))
+ }
+}
+
+class SelectAminoAcid {
+ constructor(rules) {
+ this.rules = rules
+
+ this.id ='amino-acid-select'
+ }
+
+ enter() {
+ const selector = this.rules.aminoAcidSelector
+ this.codon = this.rules.currentGenome.selectedCodon.value
+ this.expected = AminoAcid.codonMap[this.codon]
+ let x = selector.elt.querySelector('#amino-acid-selector .codon').innerHTML =
+ this.codon
+
+ selector.onItemSelected = this.handleItemSelected.bind(this)
+ selector.attach(this.selectedNucleotide)
+
+ this.rules.aminoAcidSelector.attach()
+ }
+
+ exit() {
+ this.rules.aminoAcidSelector.detach()
+ }
+
+ validSelection(aminoAcid) {
+ console.debug('aa:', this.expected)
+ return aminoAcid == this.expected
+ }
+
+ handleItemSelected(aminoAcid) {
+ console.debug('selected', aminoAcid)
+ if (!this.validSelection(aminoAcid)) {
+ this.rules.error.innerHTML =
+ `The codon ${this.codon} does not code for ${aminoAcid}`
+ this.rules.next(new ShowError(this.rules, this))
+ return
+ }
+ this.rules.next(new MarkAsLethal(this.rules))
+ }
+}
+
+class MarkAsLethal {
+ constructor(rules) {
+ this.rules = rules
+
+ this.id = 'mark-as-lethal'
+ }
+
+ enter() {
+ // Enable lethal/non-lethal selector.
+
+ // Attach validator to selector and change state if possible.
+ }
+
+ exit() {
+ // Disable lethal/non-lethal selector.
+
this.rules.iterations--
if (this.rules.isLastIteration) {
this.rules.next(new DoNothing(this.rules))
@@ -241,10 +303,11 @@ class ShowError {
}
class Rules {
- constructor(die, instructions, genomeList, nucleotideSelector, cloneButton, remainingIterations, printButton, errors) {
+ constructor(die, instructions, genomeList, aminoAcidSelector, nucleotideSelector, cloneButton, remainingIterations, printButton, errors) {
this.die = new Die(die)
this.instructions = instructions
this.genomeList = new GenomeList(genomeList)
+ this.aminoAcidSelector = new AminoAcidSelector(aminoAcidSelector)
this.nucleotideSelector = new NucleotideSelector(nucleotideSelector)
this.cloneButton = cloneButton
this.remainingIterations = remainingIterations
@@ -259,6 +322,8 @@ class Rules {
this._debugStartAtRollForMutation()
} else if (false) {
this._debugStartAtPerformMutation(4)
+ } else if (true) {
+ this._debugStartAtSelectAminoAcid()
} else if (false) {
this._debugStartWithError()
} else {
@@ -301,6 +366,14 @@ class Rules {
this.currentGenome.selectedNucleotide = nucleotide
}
+ _debugStartAtSelectAminoAcid() {
+ this.currentState = new SelectAminoAcid(this)
+ this.die.value = 15
+ const nucleotide = this.currentGenome.nucleotides[15]
+ nucleotide.value = 'A'
+ this.currentGenome.selectedNucleotide = nucleotide
+ }
+
_debugStartWithError() {
this.currentState = new ShowError(this, new CloneNucleotide(this))
this.error.innerHTML = 'test an error'