Skip to content

Commit

Permalink
better implementatation, use number of points/square according to scr…
Browse files Browse the repository at this point in the history
…een width and speed, add sound, add auto fullscreen on play, add circle option
  • Loading branch information
Nico Aymet committed May 31, 2020
1 parent 0960252 commit 29cd611
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 60 deletions.
51 changes: 23 additions & 28 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,29 @@
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
</head>
<body>
<div id="app" v-bind:style="{ backgroundColor: background}">
<div>
<b-navbar type="dark" variant="dark" fixed="top" v-show="menu">
<b-navbar-brand>EMDR</b-navbar-brand>
<b-navbar-nav>
<b-form inline>
<b-button-group class="mx-1">
<b-button :pressed.sync="isRun" v-if="isRun" variant="primary">Para [↵]</b-button>
<b-button :pressed.sync="isRun" v-else variant="primary">Inicia [↵]</b-button>
<b-button v-on:click="reset" variant="danger">Reset [R]</b-button>
</b-button-group>
<b-form-select v-model="direction" :options="directions" class="mx-1"></b-form-select>
<b-form-spinbutton v-model="speed" min="1" max="240" :formatter-fn="speedFormatter" class="mx-1"></b-form-spinbutton>
<b-form-spinbutton v-model="durationTotal" min="1" max="999" :formatter-fn="durationTotalFormatter" class="mx-1"></b-form-spinbutton>
<b-form-spinbutton v-model="width" min="1" max="100" :formatter-fn="widthFormatter" class="mx-1"></b-form-spinbutton>
<verte v-model="background" model="rgb" class="mx-1"></verte>
<verte v-model="foreground" model="rgb" class="mx-1"></verte>
<b-form-checkbox v-model="sound" size="lg" class="mx-1">Sonido [S]</b-form-checkbox>
</b-form>
</b-navbar-nav>
<b-navbar-nav class="ml-auto">
<b-button :pressed.sync="menu" title="Quita menu" variant="outline-primary" :class="{'btn-primary':menu==true}">[☰]</b-button>
<b-button :pressed.sync="fullscreen" title="Pantalla Completa" variant="outline-primary" :class="{'btn-primary':fullscreen==true}">[F]</b-button>
</b-navbar-nav>
</b-navbar>
<div id="emdr-squares">
<span class="emdr-square" v-for="n in squareNumber" v-bind:style="{ backgroundColor: ( n == squareActive ? foreground : background ), width: width + 'px', height: width + 'px' }"></span>
</div>
<div id="app" v-bind:style="{ backgroundColor: background, cursor: (isRun ? 'none' : '')}">
<b-navbar type="dark" variant="dark" fixed="top" v-show="menu">
<b-navbar-brand>EMDR</b-navbar-brand>
<b-navbar-nav>
<b-form inline>
<b-button :pressed.sync="isRun" v-if="isRun" variant="danger" class="mx-1">Para [↵]</b-button>
<b-button :pressed.sync="isRun" v-else variant="success" class="mx-1">Inicia [↵]</b-button>
<b-form-select v-model="direction" :options="directions" class="mx-1"></b-form-select>
<b-form-spinbutton v-model="speed" min="1" max="240" :formatter-fn="speedFormatter" class="mx-1"></b-form-spinbutton>
<b-form-spinbutton v-model="durationTotal" min="1" max="999" :formatter-fn="durationTotalFormatter" class="mx-1"></b-form-spinbutton>
<b-form-spinbutton v-model="width" min="1" max="100" :formatter-fn="widthFormatter" class="mx-1"></b-form-spinbutton>
<verte v-model="background" model="rgb" class="mx-1"></verte>
<verte v-model="foreground" model="rgb" class="mx-1"></verte>
<b-form-checkbox v-model="circle" size="lg" class="mx-1">Circulitos [C]</b-form-checkbox>
<b-form-checkbox v-model="sound" size="lg" class="mx-1">Sonido [S]</b-form-checkbox>
</b-form>
</b-navbar-nav>
<b-navbar-nav class="ml-auto">
<b-button-close v-on:click="close"></b-button-close>
</b-navbar-nav>
</b-navbar>
<div id="emdr-squares">
<span v-bind:class="[circle ? 'circle' : '', 'emdr-square']" v-for="n in squareNumber" v-bind:style="{ backgroundColor: ( n == squareActive ? foreground : background ), width: width + 'px', height: width + 'px' }"></span>
</div>
</div>
<script src="dist/app.js"></script>
Expand Down
146 changes: 114 additions & 32 deletions src/app.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Vue from 'vue';
import { BootstrapVue, IconsPlugin } from 'bootstrap-vue';
import { BootstrapVue, BButton } from 'bootstrap-vue';
Vue.component('b-button', BButton)
Vue.use(BootstrapVue);
Vue.use(IconsPlugin);
import Verte from 'verte';
import 'verte/dist/verte.css';
var app = new Vue({
Expand All @@ -15,9 +15,10 @@ var app = new Vue({
{value: '2', text: 'Oblicua 2 [2]'},
],
direction: 'H',
speed: 60,
speed: 120,
durationTotal: 30,
startRun: 0,
startRound: 0,
runDirection: 0,
width: 30,
background: 'rgb(0,0,0)',
Expand All @@ -29,14 +30,15 @@ var app = new Vue({
windowWidth: window.innerWidth,
windowHeight: window.innerHeight,
squareActive: 1,
intervalHandler: null,
circle: false,
roundProgress: null,
},
computed: {
squareNumber: function () {
return Math.floor(this.windowWidth / this.width);
return Math.min(Math.floor(this.windowWidth / this.width), Math.ceil(this.windowWidth / this.speed));
},
changeInterval: function () {
return (((60 / this.speed) / this.squareNumber) * 1000);
roundInterval: function () {
return (((60 / this.speed)) * 1000);
}
},
methods: {
Expand All @@ -51,36 +53,68 @@ var app = new Vue({
},
reset() {
this.isRun = false;
this.squareActive = 1;
this.startRun = 0;
this.startRun = null;
this.startRound = null;
this.runDirection = 0;
this.squareActive = 1;
},
nextSquare() {
if (this.squareActive <= 1) {
this.runDirection = 0;
this.squareActive = 1;
nextSquare(timestamp) {
if (!this.isRun) {
return;
}
if (this.squareActive >= this.squareNumber) {
this.runDirection = 1;
this.squareActive = this.squareNumber;
if (!this.startRun) {
this.startRun = timestamp;
this.startRound = timestamp;
}

this.roundProgress = (timestamp - this.startRound) / this.roundInterval;

if (this.runDirection == 0) {
this.squareActive++;
var nextSquareActive = Math.ceil(this.roundProgress * this.squareNumber);
if (nextSquareActive >= this.squareNumber) {
this.startRound = timestamp;
this.runDirection = 1;
this.squareActive = this.squareNumber;
if (this.sound) {
playSound("right");
}
} else {
this.squareActive = nextSquareActive;
}
} else {
this.squareActive--;
var nextSquareActive = Math.ceil((1 - this.roundProgress) * this.squareNumber);
if (nextSquareActive <= 1) {
this.startRound = timestamp;
this.runDirection = 0;
this.squareActive = 1;
if (this.sound) {
playSound("left");
}
} else {
this.squareActive = nextSquareActive;
}
}
var self = this;
this.intervalHandler = setTimeout(function () {
self.nextSquare();
}, this.changeInterval);
window.requestAnimationFrame(this.nextSquare);
},
close() {
document.exitFullscreen();
},
},
watch: {
isRun: function (val) {
if (val == true) {
this.nextSquare();
if (val) {
this.menu = false;
this.startRun = null;
if (document.fullscreenEnabled) {
document.documentElement.requestFullscreen();
}
if (this.sound) {
playSound("left");
}
window.requestAnimationFrame(this.nextSquare);
} else {
clearTimeout(this.intervalHandler);
this.menu = true;
this.reset();
}
},
},
Expand All @@ -91,14 +125,12 @@ var app = new Vue({
case 32: //space
this.isRun = !this.isRun;
break;
case 115: //s
case 27: // ESC
this.isRun = false;
break;
case 83: //S
this.sound = !this.sound;
break;
case 114://r
case 82: //R
this.reset();
break;
case 37: //ArrowLeft
if (this.durationTotal > 1) {
this.durationTotal--;
Expand Down Expand Up @@ -126,8 +158,24 @@ var app = new Vue({
case 77: //m
this.menu = !this.menu;
break;
case 67: //c
this.circle = !this.circle;
break;
case 72: //h
this.direction = 'H';
break;
case 86: //v
this.direction = 'V';
break;
case 49: //1
case 97: //1
this.direction = '1';
break;
case 50: //2
case 98: //2
this.direction = '2';
break;
default:
console.log(e);
break;
}
}.bind(this));
Expand All @@ -136,4 +184,38 @@ var app = new Vue({
this.windowHeight = window.innerHeight;
}.bind(this));
}
})
});

// https://jsfiddle.net/teropa/bwxwhoqr/1/
const LENGTH_MS = 100;

const REAL_TIME_FREQUENCY = 442;
const ANGULAR_FREQUENCY = REAL_TIME_FREQUENCY * 2 * Math.PI;
const LENGTH = (LENGTH_MS / 1000) * 44100;

let audioContext = new AudioContext();
let myLeftChannelBuffer = audioContext.createBuffer(2, LENGTH, 44100); // 2 channels
let myRightChannelBuffer = audioContext.createBuffer(2, LENGTH, 44100); // 2 channels
let myLeftArray = myLeftChannelBuffer.getChannelData(0);
let myRightArray = myRightChannelBuffer.getChannelData(1);
for (let sampleNumber = 0; sampleNumber < LENGTH; sampleNumber++) {
myLeftArray[sampleNumber] = generateSample(sampleNumber);
myRightArray[sampleNumber] = generateSample(sampleNumber);
}

function generateSample(sampleNumber) {
let currentTime = sampleNumber / 44100;
let currentAngle = currentTime * ANGULAR_FREQUENCY;
return Math.sin(currentAngle);
}

function playSound(channel) {
let src = audioContext.createBufferSource();
if (channel == 'left') {
src.buffer = myLeftChannelBuffer;
} else if (channel == 'right') {
src.buffer = myRightChannelBuffer;
}
src.connect(audioContext.destination);
src.start();
}
7 changes: 7 additions & 0 deletions src/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,18 @@ html, body {

#emdr-squares{
display: flex;
justify-content: space-between;
height: 100%;
width: 100%;
line-height: 100%;
}

.emdr-square{
display: inline-block;
margin: auto;
/*border: 1px solid white;*/
}

.emdr-square.circle{
border-radius: 50%;
}

0 comments on commit 29cd611

Please sign in to comment.