<template> <div class="container"> <!-- G4killer multiple form --> <app-form @submit="calculate" ref="calculateForm" :validator="$v"> <label class="mandatory">Sequences</label> <!--Inputs --> <textarea class="form-control" v-model="sequences" rows="10"></textarea> <br /> <div class="alert alert-danger" v-if="$v.$anyError"> <!--Allert messages --> <div v-if="!$v.sequences.required">Sequence is required.</div> <div v-if="!$v.sequences.numLines">The limit is {{ $v.sequences.$params.numLines.amount }} rows.</div> </div> <label class="mandatory">Target G4 hunter score</label> <div class="row"> <div class="col-md-3"> <input type="number" class="form-control" step="0.1" min="1.2" max="2" required v-model="$v.threshold.$model" /> </div> <div class="col-md-2"> <button type="submit" class="btn btn-primary">Calculate</button> </div> </div> </app-form> <hr /> <!-- Results --> <div v-if="results"> <h2>Results</h2> <br /> <table v-for="result in results" class="table table-striped"> <tbody> <!-- Result table header --> <tr> <th class="text-center">Original sequence</th> <th class="text-center">Score</th> <th class="text-center">Show mutations</th> </tr> <!-- Result table content --> <tr> <td class="sequence text-center text-bold"> <Highlight :sequence="result.originSequence"></Highlight> </td> <td class="text-center">{{ result.originScore | number }}</td> <td class="text-center"> <!-- Button show mutation results --> <b-button variant="primary" v-if="!result.showMutated" @click="toggleShowMutations(result)" >Show</b-button > <b-button variant="primary" v-if="result.showMutated" @click="toggleShowMutations(result)">Hide</b-button> </td> </tr> <!-- Mutated sequences header --> <tr v-if="result.showMutated"> <th class="text-center">Mutated sequence</th> <th class="text-center">Score</th> <th class="text-center">Details</th> </tr> <!-- Mutated sequences content --> <template v-for="mutationSequence in result.mutationSequences"> <tr v-if="result.showMutated"> <td class="sequence text-center text-bold"> <Highlight :sequence="mutationSequence.sequence"></Highlight> </td> <td class="text-center">{{ result.mutationScore | number }}</td> <td class="text-center"> <b-button variant="primary" v-if="!mutationSequence.showDetail" @click="toggleShowDetail(mutationSequence)" >Show</b-button > <b-button variant="primary" v-if="mutationSequence.showDetail" @click="toggleShowDetail(mutationSequence)" >Hide</b-button > </td> </tr> <!-- Mutated sequences detail content --> <tr v-if="mutationSequence.showDetail"> <td colspan="3"> <pre> {{ mutationSequence.origin }} {{ mutationSequence | difference }} {{ mutationSequence.sequence }} </pre> </td> </tr> </template> </tbody> </table> </div> </div> </template> <script> import Highlight from '@/components/core/visualisation/highlight' import Formatters from '@/formatters' import AppForm from '@/components/core/app-form' import { required, minValue, maxValue, decimal, helpers } from 'vuelidate/lib/validators' const numLines = lines => { return helpers.withParams({ type: 'numLines', amount: lines }, s => { return ( s.split('\n').filter(r => { return r.trim() != '' }).length <= lines ) }) } export default { data() { return { sequences: '', threshold: 1.4, showRes: false, results: null, differences: '', } }, validations: { sequences: { required, numLines: numLines(20), }, threshold: { required, decimal, minValue: minValue(1.2), maxValue: maxValue(2), }, }, components: { Highlight, AppForm, }, filters: { number: Formatters.number, difference: function(mutationSequence) { return mutationSequence.origin.replace(/W/g, '-').replace(/\w/g, '|') }, }, methods: { calculate() { this.results = [] this.differences = [] let promises = [] this.sequences.split('\n').forEach(item => { item = item.trim() if (item.length > 0) { let p = this.$http .post('/analyse/g4killer', { sequence: item, threshold: this.threshold, }) .then( resp => { let sequence = resp.data console.log(sequence) sequence.showMutated = false sequence.mutationSequences = resp.data.mutationSequences.map(ms => ({ origin: ms, sequence: this.replaceMutationSequence(ms), showDetail: false, })) this.results.push(sequence) }, () => { //TODO } ) promises.push(p) } }) Promise.all(promises).finally(() => { this.$refs.calculateForm.enable() this.showRes = true }) }, replaceMutationSequence(mutationSequence) { const replacement = ['A', 'T'] return mutationSequence.replace(/W/g, () => { return replacement[Math.floor(Math.random() * replacement.length)] }) }, toggleShowDetail(mutationSequence) { mutationSequence.showDetail = !mutationSequence.showDetail }, toggleShowMutations(sequence) { sequence.showMutated = !sequence.showMutated }, }, mounted() { if (this.$route.query.threshold) { this.threshold = parseFloat(this.$route.query.threshold) } if (this.$route.query.sequence) { this.sequence = this.$route.query.sequence this.calculate() } }, } </script> <style scoped> textarea { font-family: monospace; } </style>