<template> <div class="container"> <app-form @submit="calculate" ref="calculateForm" :validator="$v"> <div class="row"> <div class="col-md-5"> <label class="mandatory">Sequence</label> <input type="text" class="form-control" v-model="$v.sequence.$model" required /> <br /> </div> <div class="col-md-3"> <label class="mandatory">Target G4 hunter score</label> <input type="number" class="form-control" step="0.1" min="0" max="2" required v-model="$v.threshold.$model" /> <br /> </div> <div class="col-md-4"> <label>On complementary sequence</label> <b-form-checkbox class="form-control switch" name="check-button" v-model="onComplementary" switch> <b>(Complementary: {{ onComplementary ? 'On' : 'Off' }})</b> </b-form-checkbox> <br /> </div> </div> <div class="alert alert-danger" v-if="$v.$anyError"> <div v-if="!$v.sequence.required">Sequence is required.</div> <div v-if="!$v.sequence.maxLength">Sequence max length is {{ $v.sequence.$params.maxLength.max }}.</div> <div v-if="!$v.threshold.required">Threshold is required.</div> <div v-if="!$v.threshold.decimal"> Threshold must be decimal number. </div> <div v-if="$v.threshold.$model <= 1.2"> The probability of G-quadruplex formation with G4Hunter score below 1.2 is low. </div> <div v-if="!$v.threshold.maxValue">Maximal value of threshold is {{ $v.threshold.$params.maxValue.max }}.</div> </div> <div class="alert alert-danger" v-if="analyse">Analyse failed: {{ analyse.errors[0].defaultMessage }}</div> <button type="submit" class="btn btn-primary">Calculate</button> </app-form> <hr /> <div v-if="result"> <h2>Result</h2> <table class="table table-striped"> <tbody> <tr> <th class="text-left">Original sequence</th> <th class="text-left">Score</th> <th class="text-center"></th> </tr> <tr> <td class="sequence text-left text-bold"> <Highlight :sequence="result.originSequence" /> </td> <td class="text-left">{{ result.originScore | number }}</td> <td class="text-center"></td> </tr> <template v-if="result.mutationSequences"> <tr> <th class="text-left" v-if="result.mutationSequences.length == 1"> A mutated sequence </th> <th class="text-left" v-else>List of mutated sequences</th> <th class="text-left">Score</th> <th class="text-center">Details</th> </tr> </template> <template v-for="mutationSequence in result.mutationSequences"> <tr> <td class="sequence text-monospace text-bold"> <Highlight :sequence="mutationSequence.sequence" :mask="mutationSequence.origin"> </Highlight> </td> <td class="text-left">{{ result.mutationScore | number }}</td> <td class="text-center"> <b-button variant="primary" v-if="!mutationSequence.showDetail" @click="toggleShowDetail(mutationSequence)" > Show detail </b-button> <b-button variant="primary" v-if="mutationSequence.showDetail" @click="toggleShowDetail(mutationSequence)" > Hide detail </b-button> </td> </tr> <tr v-if="mutationSequence.showDetail"> <td class="text-center" colspan="3"> <G4KillerDetail :sequence="result.originSequence" :mutation="mutationSequence"> </G4KillerDetail> </td> </tr> </template> </tbody> </table> <div class="alert alert-warning" v-if="result && !result.mutationSequences"> The target score {{ threshold }} is below the G4Hunter score of the sequence. <b>No mutation is needed!</b> </div> <hr /> </div> <div class="card bg-light"> <div class="card-body"> Please insert your nucleic acid sequence and choose desired G4 hunter score. </div> </div> </div> </template> <script> import Highlight from '@/components/core/visualisation/highlight' import G4KillerDetail from './g4killer-detail' import Formatters from '@/formatters' import AppForm from '@/components/core/app-form' import { decimal, maxLength, maxValue, minValue, required } from 'vuelidate/lib/validators' export default { components: { Highlight, G4KillerDetail, AppForm, }, data() { return { sequence: '', threshold: 1.0, result: null, differences: '', onComplementary: false, analyse: null, } }, validations: { sequence: { required, maxLength: maxLength(100), }, threshold: { required, decimal, minValue: minValue(0), maxValue: maxValue(2), }, }, methods: { calculate() { this.result = null this.differences = [] this.$http .post('/analyse/g4killer', { sequence: this.sequence, threshold: this.threshold, onComplementary: this.onComplementary, }) .then(response => { this.result = response.data this.analyse = null this.result.mutationSequences = response.data.mutationSequences.map(ms => ({ origin: ms, sequence: this.replaceMutationSequence(ms), showDetail: false, })) }) .catch(error => { if (error.response) { this.analyse = error.response.data } }) .finally(() => { this.$refs.calculateForm.enable() }) }, 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 }, }, 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.onComplementary = this.$route.query.onComplementary this.calculate() } }, filters: { number: Formatters.number, difference: function(mutationSequence) { return mutationSequence.origin.replace(/W/g, '-').replace(/\w/g, '|') }, }, } </script> <style scoped> .sequence { max-width: 400px; overflow: hidden; text-overflow: ellipsis; } .switch { border: 0; } </style>