QutBioacousticsResearchGroup/bioacoustic-workbench

View on GitHub
app/assets/templates/rapid_scanning_experiment.html

Summary

Maintainability
Test Coverage
<div ng-controller="RapidScanCtrl" xmlns="http://www.w3.org/1999/html">

<style type="text/css">
.experimentContainer {
    width: 100%;
    text-align: center;
    height: 800px;
    line-height: normal;
    margin-top: 22px;
}

.experimentContainer p {
    margin: 9px auto;
}

.experimentContainer em {
    font-style: normal;
    font-weight: bolder;
    font-family: monospace;
    color: #464646;
    font-size: xx-large;
    padding-left: 0.2em;
    padding-right: 0.2em;
    padding-top: 0.1em;

    border-radius: 3px;

    -webkit-animation: animateBg 1.0s linear 0 infinite alternate;

    /*box-shadow: rgb(222, 224, 222) 1px 1px 10px;*/
    /*background-color: rgba(255,255,255,0.6);*/

}

@-webkit-keyframes animateBg {
    from {
        background-color: rgba(255, 255, 255, 0.3);
        box-shadow: rgba(253, 255, 253, 0.3) 1px 1px 10px;
    }

    to {
        background-color: rgb(255, 255, 255);
        box-shadow: rgb(255, 255, 255) 1px 1px 10px;
    }
}

.imageList {
    list-style: none;
    margin: 0;
    padding: 0;

}

.imageList li {
    margin: 0;
    padding: 0;
}

.instructions {
    font-size: 16px;

}

.instructions>div {
    width: 66%;
    margin: 0 auto;;
    text-align: left;
}

    /*.instructions > div img {*/
    /*display: block;*/
    /*margin:  0 auto;*/
    /*}*/

.demoSpectrogram {
    position: relative;
    width: 100%;

}

.demoSpectrogram span {
    color: #f3f3f3;
    font-size: x-large;
    font-weight: bold;
    padding: 0.05em 0.2em;
    text-shadow: black 0px 0px 5px;

}

.demoSpectrogram *:not(.baseImage) {
    -webkit-animation: fadeIn 4.0s ease-in-out 0.25s infinite alternate;
}

@-webkit-keyframes fadeIn {
    from {
        opacity: 1.0;
    }
    to {
        opacity: 0.0;
    }
}

.overlay {
    position: absolute;
    top: 0;
    left: 0;

}

.grunt {
    position: absolute;
    top: 190px;
    left: 28px;
}

.inhale {
    position: absolute;
    top: 60px;
    left: 527px;;
}

.arrow_box {
    /*position: relative;*/
    /*background: rgba(0, 255, 0, 1.0);*/
    border: 2px solid #00ff00;
}

.arrow_box:after, .arrow_box:before {
    top: 100%;
    border: solid transparent;
    content: " ";
    height: 0;
    width: 0;
    position: absolute;
    pointer-events: none;
}

.arrow_box:after {
    border-color: rgba(111, 213, 100, 0);
    border-top-color: rgba(111, 213, 100, 0.5);
    border-width: 10px;
    left: 50%;
    margin-left: -10px;
}

.arrow_box:before {
    border-color: rgba(0, 255, 0, 0);
    border-top-color: #00ff00;
    border-width: 13px;
    left: 50%;
    margin-left: -13px;
}

.experimentContainer .header {
    height: 65px;
}

.countDownTimer {
    position: absolute;
    right: 30px;
    top: -120px;
    width: 100px;
    height: 120px;
}

.spectrogramImage {
    -webkit-box-shadow: 2px 2px 7px black;
    margin: 5px auto;
    height: 256px;
    background-image: -webkit-gradient(radial, center center, 0, center center, 506, color-stop(0, #FFFFFF), color-stop(1, #ABABAB));
    display: block;
}

.spectrogramImage p {
    margin: 0px auto;
    padding: 15px;
    font-size: 32px;

}

.detection {
    background-color: rgb(251, 255, 223);
    border-radius: 8px;
    margin: 5px 0.4%;
    width: 49%;
    display: inline-block;
    height: 70px;
    font-size: 18px;
    float: left;
    padding-top: 13px;
}

.detection p {
    color: #464646;
    height: 70px;
    margin: 0;
    padding: 0;

}

.foundNegative {
    background-color: lightskyblue;
}

.foundNegative p {
    color: blue;
}

.foundPositive {
    background-color: lightgreen;
}

.foundPositive p {
    color: green;
}

.spinner {
    -webkit-mask-box-image: -webkit-radial-gradient(center, ellipse cover, rgba(0, 0, 0, 1) 68%, rgba(0, 0, 0, 0) 69.5%);
    background: #eee;
    width: 100px;
    height: 100px;
    position: relative;
}

.spinner-inner {
    position: absolute;
    top: 0;
    left: 0;
    background: transparent;
    border-width: 50px;
    width: 0;
    height: 0;
    border-style: solid;
    border-color: transparent;
    border-top-color: rgb(72, 129, 54); /*rgba(200, 200, 200, 1);*/
    -webkit-transform: rotate(-45deg);
    /*-webkit-animation: inner 15s linear infinite;*/
}

.spinner-mask {
    position: absolute;
    top: 1px;
    left: 0px;
    background: transparent;
    border-width: 50px;
    width: 0;
    height: 0;
    border-style: solid;
    border-color: transparent;
    border-top-color: #eee;
    -webkit-transform: rotate(-45deg);
    /*-webkit-animation: mask 15s linear infinite;*/
}

.spinner-mask:after, .spinner-mask-two {
    display: block;
    content: '';
    opacity: 0;
    position: absolute;
    top: 1px;
    left: 0px;
    background: transparent;
    border-width: 50px;
    width: 0;
    height: 0;
    border-style: solid;
    border-color: transparent;
    border-top-color: rgb(72, 129, 54); /*rgba(200, 200, 200, 1);*/
    -webkit-transform: rotate(45deg);
    /*-webkit-animation: mask-two 15s linear infinite;*/
}

@-webkit-keyframes inner {
    0% {
        -webkit-transform: rotate(-45deg);
    }
    25% {
        border-left-color: transparent;
    }
    26% {

        border-left-color: rgba(72, 129, 54, 1); /*rgba(200, 200, 200, 1);*/
    }
    50% {
        border-bottom-color: transparent;
    }
    51% {
        border-bottom-color: rgba(72, 129, 54, 1); /*rgba(200, 200, 200, 1);*/
    }
    75% {
        border-right-color: transparent;
    }
    76% {
        border-right-color: rgba(72, 129, 54, 1);
    }
    100% {
        -webkit-transform: rotate(315deg);
        border-left-color: rgba(72, 129, 54, 1); /*rgba(200, 200, 200, 1);*/
        border-bottom-color: rgba(72, 129, 54, 1); /*rgba(200, 200, 200, 1);*/
        border-right-color: rgba(72, 129, 54, 1); /*rgba(200, 200, 200, 1);*/
    }
}

@-webkit-keyframes mask {
    0% {
        -webkit-transform: rotate(-45deg);
    }
    75% {
        -webkit-transform: rotate(-45deg);
    }
    100% {
        -webkit-transform: rotate(45deg);
    }
}

@-webkit-keyframes mask-two {
    0% {
        opacity: 0;
    }
    25% {
        opacity: 0;
    }
    26% {
        opacity: 1;
    }
    100% {
        opacity: 1;
    }
}

@-webkit-keyframes whee {
    from {
        -webkit-transform: rotate(0deg);
        -webkit-filter: sepia() hue-rotate(0deg) contrast(95%);
    }
    to {
        -webkit-transform: rotate(360deg);
        -webkit-filter: sepia() hue-rotate(360deg) contrast(95%);
    }
}


</style>

<div class="experimentContainer">

    <div class="instructions" ng-show="showInstructions">
        <h3>Instructions for part <em>{{bigScope.step}}</em></h3>
        <h4>{{stepResults.name}}, exposure <em>{{stepResults.speed.speed}}</em>s</h4>

        <div>
            <p>
                A series of images will be shown one after another - like flash cards.
                These images are called
                <a href="http://en.wikipedia.org/wiki/Spectrogram"
                   target="_blank"
                   class="hint hint--info hint--bottom"
                   data-hint="A spectrogram is a time/frequency graph for the visualisation of data – e.g. audio data. ">
                    spectrograms</a>.
            </p>

            <p>
                In these images, we are looking for a specific pattern representative of a target species.
                In this experiment we are looking for Koalas. When Koalas vocalise they produce a spectrogram that looks
                like this (the two types Koala vocalisations have green boxes drawn around them): </p>

            <div class="demoSpectrogram">
                <img class="baseImage" src="/experiment_assets/koala_demo3.jpg">
                <img class="overlay" src="/experiment_assets/overlays.png">
                <span class="grunt arrow_box">snore</span>
                <span class="inhale arrow_box">snort</span>
            </div>
            <p>
                Study this image carefully before proceeding.
            </p>

            <p>
                During the experiment, you must choose for each flash card (spectrogram image) whether one (or more)
                Koala
                vocalisations are present in the image or not.
                <br/>
                <span ng-switch on="bigScope.results.yesOnly">
                    <span ng-switch-when="false">
                        To indicate that you have not seen any Koalas press the <em>&lt;left arrow&gt;</em> key.
                        <br/>
                        To indicate that you saw one or more Koalas press the <em>&lt;right arrow&gt;</em> key.
                    </span>
                    <span ng-switch-when="true">
                        To indicate that you saw one or more Koalas press the <em>&lt;right arrow&gt;</em> key.
                        <br/>
                        To un-indicate (change your answer) press the <em>&lt;left arrow&gt;</em> key.
                    </span>
                </span>
            </p>

            <p>
                You are doing test number <em>{{bigScope.step}}</em> of
                <em>{{bigScope.spec.experimentSteps.length}}</em>.
                <br/>
                This test will show each flash card (spectrogram image) for <em
                    style="font-weight: bolder; font-size: xx-large">{{stepResults.speed.speed | number:2}}</em>
                seconds.
                <br/>
                This test will show <em>{{stepResults.flashes.length}}</em> flash cards (spectrogram images).
            </p>

            <p ng-show="stepResults.extraInstructions || stepResults.speed.notes">
                {{stepResults.extraInstructions}}
                <span ng-bind-html-unsafe="stepResults.speed.notes"> </span>
            </p>

            <p ng-show="totalDownloaded < stepResults.flashes.length">
                The experiment is downloading, please wait:
                <progress value="{{totalDownloaded + 1}}" max="{{stepResults.flashes.length + 1}}"></progress>
            </p>
            <p ng-show="totalDownloaded == stepResults.flashes.length">

                The test will start immediately after you press the button below - get ready.
            </p>
        </div>
        <button ng-disabled="totalDownloaded != stepResults.flashes.length" ng-click="start()">I understand the
            instructions, let's go
        </button>
    </div>

    <div style="height:600px; vertical-align: middle;" ng-show="!showInstructions"
         ui-keydown="{'17-ctrl':'hit($event)', '16-shift':'hit($event)', 'left':'hit($event)', 'right':'hit($event)', 'space': 'pauseOrResume($event)'}"
         tabindex="1" id="experimentKeyPressDiv">
        <div id="{{'step_' +($index + 1)}}">
            <!--ng-repeat="step in bigScope.spec.experimentSteps" ng-show="bigScope.step == $index + 1">-->
            <div class="header">
                <h4>{{stepResults.name}}, exposure {{stepResults.speed.speed}}s</h4>
                {{stepResults.extraInstructions}}
                <p ng-bind-html-unsafe="stepResults.speed.notes"></p>
            </div>

            <div>
                <div class=""
                     ng-show="segment.show"
                     ng-class="clear-pseudo"
                     style="margin: 1em auto; position: relative"
                     ng-style="{width: SPECTROGRAM_WIDTH + 'px'}">

                    <!--ng-repeat="segment in stepResults.flashes" ng-show="segment.show"-->

                    <div class="countDownTimer">
                        <div>Flash timer</div>
                        <div class="spinner">
                            <div class="spinner-inner"
                                 ng-style="{ '-webkit-animation': 'inner ' + animationText, '-webkit-animation-play-state':  animationControl()}"
                                    ></div>
                            <div class="spinner-mask"
                                 ng-style="{ '-webkit-animation': 'mask ' + animationText, '-webkit-animation-play-state':  animationControl() }"
                                    ></div>
                            <div class="spinner-mask-two"
                                 ng-style="{ '-webkit-animation':  'mask-two '+ animationText, '-webkit-animation-play-state':  animationControl() }"
                                    ></div>
                        </div>
                    </div>


                    <div class="spectrogramImage"
                         ng-hide="countDown == 0"
                            >
                        <p>Place your hands on the keyboard.</p>

                        <p>The first flash card will appear in:</p>

                        <p>
                            {{countDown}}
                        </p>
                    </div>
                    <ul class="imageList" ng-style="{width: SPECTROGRAM_WIDTH + 'px'}">
                        <li ng-repeat="segment in stepResults.flashes" ng-show="segment.show">
                            <img class="spectrogramImage" ng-show="countDown == 0"

                                 ng-src="{{segment.imageLink}}">
                        </li>
                    </ul>
                    <!-- baw-image-loaded="segment.downloaded"-->

                    <div>
                        <span style="float:left">Starting time: <span class="relative-chunk-time hint--right">{{ft(segment.start)}}</span></span>

                        Duration: <span class="duration hint--bottom">{{ft(segment.end - segment.start)}}</span>
                        <span style="float:right">Ending time: <span class="relative-chunk-time hint--left">{{ft(segment.end)}}</span></span>
                    </div>

                    <p ng-hide="showDoneButton" class="instructions">
                        Press the appropriate key on your keyboard if you see a {{stepResults.patternName}}
                        vocalisation
                    </p>

                    <div class="clear-pseudo" ng-switch on="bigScope.results.yesOnly">
                        <div ng-switch-when="false" class="detection" ng-class="{'foundNegative': segment.detected == 'negative'}">
                            <p ng-hide="segment.detected == 'negative'">I see no {{stepResults.patternName}}s
                                <br/><em>&lt;left arrow&gt;</em>
                            </p>

                            <p ng-show="segment.detected == 'negative'">I see no {{stepResults.patternName}}s</P>
                        </div>
                        <div class="detection"
                             ng-class="{'foundPositive': segment.detected == 'positive' }"
                             ng-style="{'float':bigScope.results.yesOnly && 'none' || undefined}"   >
                            <p ng-hide="segment.detected == 'positive' ">I see a {{stepResults.patternName}}
                                <br/><em>&lt;right arrow&gt;</em></P>

                            <p ng-show="segment.detected  == 'positive' ">I saw a {{stepResults.patternName}}</P>
                        </div>
                    </div>
                    <br/>

                    <button class="clear-pseudo" style="margin: 0 auto;" ng-click="pauseOrResume()">
                        <span ng-hide="paused">Pause</span>
                        <span ng-show="paused">Resume</span>
                    </button>


                </div>

                <div ng-hide="showDoneButton">Progress through flash cards ({{currentFlash + 1}}/{{stepResults.flashes.length}})
                    <meter value="{{currentFlash + 1}}" max="{{stepResults.flashes.length}}"></meter>
                </div>

                <div class="class" ng-show="showDoneButton">

                    <p>
                        Part {{bigScope.step}} of the experiment is done.
                    </p>

                    <p>
                        You can pause here to take a break if you like.
                    </p>

                    <button ng-click="end()">Go to next part</button>
                </div>
            </div>
        </div>
    </div>


</div>
</div>