Improve model view and add BPM
This commit is contained in:
parent
5257102b3d
commit
a4b63c8657
14 changed files with 10762 additions and 57 deletions
BIN
assets/img/gadgety-favicon.png
Normal file
BIN
assets/img/gadgety-favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 472 B |
10449
assets/img/gadgety-favicon.svg
Normal file
10449
assets/img/gadgety-favicon.svg
Normal file
File diff suppressed because it is too large
Load diff
After Width: | Height: | Size: 506 KiB |
2
assets/js/moduleData.json
Normal file
2
assets/js/moduleData.json
Normal file
|
@ -0,0 +1,2 @@
|
|||
{
|
||||
}
|
44
assets/js/moduleDataPUVIO.json
Normal file
44
assets/js/moduleDataPUVIO.json
Normal file
|
@ -0,0 +1,44 @@
|
|||
{
|
||||
"lines": [
|
||||
{
|
||||
"lines_1": [
|
||||
{
|
||||
"beats": [
|
||||
{
|
||||
"beats_1": [
|
||||
{
|
||||
"subdivisions": [
|
||||
{
|
||||
"name": "suddivisions_1",
|
||||
"offset": "12345"
|
||||
},
|
||||
{
|
||||
"name": "suddivisions_2",
|
||||
"offset": "6789"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"beats_2": [
|
||||
{
|
||||
"subdivisions": [
|
||||
{
|
||||
"name": "suddivisions_1",
|
||||
"offset": "12345"
|
||||
},
|
||||
{
|
||||
"name": "suddivisions_2",
|
||||
"offset": "6789"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -3,12 +3,10 @@
|
|||
<input v-model="divisioni" type="number" min="1" oninput="validity.valid||(value='');">
|
||||
<!--- trovare modo per prevenire scrittura di input-->
|
||||
<div class="division-wrapper">
|
||||
<div class="beat" v-for="j in nDivisioni" :key='j'>
|
||||
<div>{{randomColori()}}</div>
|
||||
<div class="suddivisione" :style="{'background-color': colore }"></div>
|
||||
<div class="suddivisione-wrapper" v-for="j in nDivisioni" :key='j' :id="'suddivisione'+j" >
|
||||
<div class="suddivisione-content" :style="{'background-color': colore }" style="max-width:1em"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <beatMenu></beatMenu>-->
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
|
@ -16,8 +14,10 @@
|
|||
name: 'beat',
|
||||
data() {
|
||||
return {
|
||||
nome:'',
|
||||
colore: 'red',
|
||||
divisioni: 1
|
||||
divisioni: 1,
|
||||
timing: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -27,27 +27,19 @@
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
checkDivisioni: function (){
|
||||
console.log("numero dell'input è" + this.nDivisioni)
|
||||
},
|
||||
randomColori: function (){
|
||||
var letters = '0123456789ABCDEF';
|
||||
var color = '#';
|
||||
for (var i = 0; i < 6; i++) {
|
||||
color += letters[Math.floor(Math.random() * 16)];
|
||||
}
|
||||
console.log(color);
|
||||
this.colore = color;
|
||||
titolo(progressivo){
|
||||
this.nome = "nomeBeat" + progressivo;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.beat{
|
||||
.suddivisione-wrapper{
|
||||
flex: 1 1 auto;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
height:1em;
|
||||
display:flex;
|
||||
}
|
||||
|
||||
.active{
|
||||
|
@ -56,7 +48,7 @@
|
|||
|
||||
input {
|
||||
background:transparent;
|
||||
width:100%;
|
||||
width:2em;
|
||||
}
|
||||
|
||||
.division-wrapper {
|
||||
|
@ -64,13 +56,8 @@ input {
|
|||
display: flex;
|
||||
}
|
||||
|
||||
.beat {
|
||||
height:1em;
|
||||
display:flex;
|
||||
flex:1 1 auto;
|
||||
}
|
||||
|
||||
.suddivisione{
|
||||
.suddivisione-content{
|
||||
flex:1 1 auto;
|
||||
border:none;
|
||||
}
|
||||
|
|
101
components/beatInfiniteLoop.vue
Normal file
101
components/beatInfiniteLoop.vue
Normal file
|
@ -0,0 +1,101 @@
|
|||
<template>
|
||||
<div class="beat-wrapper">
|
||||
<input v-model="divisioni" type="number" min="1" oninput="validity.valid||(value='');">
|
||||
<!--- trovare modo per prevenire scrittura di input-->
|
||||
<div class="division-wrapper">
|
||||
<div class="beat" v-for="j in nDivisioni" :key='j' >
|
||||
<!--<div>{{randomColori()}}</div>-->
|
||||
<div class="suddivisione" :style="{'background-color': colore }" style="max-width:1em" :id="nome">{{titolo(j)}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'beat',
|
||||
data() {
|
||||
return {
|
||||
nome:'',
|
||||
colore: 'red',
|
||||
divisioni: 1,
|
||||
timing: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
nDivisioni() {
|
||||
var n = parseInt(this.divisioni);
|
||||
return isNaN(n) ? 0 : n;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
randomColori: function (){
|
||||
var letters = '0123456789ABCDEF';
|
||||
var color = '#';
|
||||
for (var i = 0; i < 6; i++) {
|
||||
color += letters[Math.floor(Math.random() * 16)];
|
||||
}
|
||||
// console.log(color);
|
||||
this.colore = color;
|
||||
},
|
||||
getTime: function(){
|
||||
// https://stackoverflow.com/questions/288699/get-the-position-of-a-div-span-tag#288731
|
||||
var el = document.getElementById(this.nome);
|
||||
for (var lx=0, ly=0;
|
||||
el != null;
|
||||
lx += el.offsetLeft, ly += el.offsetTop, el = el.offsetParent);
|
||||
console.log("x :"+ lx+", y :"+ly);
|
||||
},
|
||||
titolo(progressivo){
|
||||
this.nome = "nomeBeat" + progressivo;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.beat{
|
||||
flex: 1 1 auto;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.active{
|
||||
background-color:black;
|
||||
}
|
||||
|
||||
input {
|
||||
background:transparent;
|
||||
width:2em;
|
||||
}
|
||||
|
||||
.division-wrapper {
|
||||
flex:1 1 auto;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.beat {
|
||||
height:1em;
|
||||
display:flex;
|
||||
flex:1 1 auto;
|
||||
}
|
||||
|
||||
.suddivisione{
|
||||
flex:1 1 auto;
|
||||
border:none;
|
||||
}
|
||||
|
||||
input[type=number]::-webkit-inner-spin-button,
|
||||
input[type=number]::-webkit-outer-spin-button {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
input[type=number] {
|
||||
-moz-appearance:textfield;
|
||||
padding-left:0.2em;
|
||||
color:lightgray;
|
||||
border:none;
|
||||
}
|
||||
</style>
|
18
components/sendButton.vue
Normal file
18
components/sendButton.vue
Normal file
|
@ -0,0 +1,18 @@
|
|||
<template>
|
||||
<div class="send-wrapper">
|
||||
<input type="submit" value="Submit">
|
||||
<input type="button" style="width:5em;height:2em;background:red;color:white;" value="Send!">
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
</style>
|
|
@ -1,26 +1,18 @@
|
|||
<template>
|
||||
<section class="sequencer" v-on:mouseover="displayControls()" v-on:mouseleave="hideControls()" >
|
||||
<div class="sequencerLine">
|
||||
<div class="slot-wrapper">
|
||||
<div class="slot" v-for="i in slotSlider" :key='i' >
|
||||
<beat v-if="euclideanList[i] === 1"></beat>
|
||||
<div v-else class="activeSlot"></div>
|
||||
<div class="slot" v-for="(slot, slotid) in euclideanList" :key="slotid">
|
||||
<beat :id="'slot'+slotid" v-if="slot === 1"></beat>
|
||||
<div v-else class="emptySlot"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="control-menu" :class="[{'displayControls': controlIsDisplayed}]">
|
||||
<range-slider class="slider" min="1" :max="maxSlots" step="1" v-model="slotSlider" v-on:input="assignEuclidean(slotSlider, pulseSlider)" ></range-slider>
|
||||
<input id="pulseSlider" v-model="maxSlots" />
|
||||
<range-slider class="slider" min="1" step="1" v-model="slotSlider" v-on:input="assignEuclidean(slotSlider, pulseSlider)" ></range-slider>
|
||||
<input id="pulseSlider"/>
|
||||
<range-slider class="slider" min="1" :max="slotSlider" step="1" v-model="pulseSlider" v-on:input ="assignEuclidean(slotSlider, pulseSlider)" ></range-slider>
|
||||
<input id="pulseSlider" value="3" v-model="assignBeat" />
|
||||
<input id="pulseSlider" value="3" />
|
||||
</div>
|
||||
<!---
|
||||
<div style="background-color:firebrick">
|
||||
<input type="range" class="slider" min="1" max="32" step="1" v-model="slotSlider" v-on:change="assignEuclidean(slotSlider, pulseSlider)" />
|
||||
<input type="range" class="slider" min="1" :max="slotSlider" step="1" v-model="pulseSlider" v-on:change="assignEuclidean(slotSlider, pulseSlider)" />
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
@ -32,13 +24,17 @@
|
|||
import beat from '~/components/beat.vue'
|
||||
|
||||
export default {
|
||||
props: [ 'line' ],
|
||||
data() {
|
||||
return{
|
||||
slotSlider: 16,
|
||||
pulseSlider: 3,
|
||||
euclideanList:[],
|
||||
controlIsDisplayed:false
|
||||
}
|
||||
// return {
|
||||
// id: line.id,
|
||||
// slotSlider: line.slotSlider,
|
||||
// pulseSlider: line.pulseSlider,
|
||||
// euclideanList: line.euclideanList,
|
||||
// controlIsDisplayed: line.controlIsDisplayed
|
||||
// };
|
||||
this.line.euclideanList = this.bjorklund(this.line.slotSlider, this.line.pulseSlider);
|
||||
return this.line;
|
||||
},
|
||||
components: {
|
||||
RangeSlider,
|
||||
|
@ -86,7 +82,6 @@
|
|||
return pattern.reverse();},
|
||||
assignEuclidean: function (a,b) {
|
||||
this.euclideanList = this.bjorklund(a,b);
|
||||
console.log(this.euclideanList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -140,6 +135,13 @@
|
|||
display:flex !important;
|
||||
}
|
||||
|
||||
.sequencerLine{
|
||||
display:flex;
|
||||
height:3em;
|
||||
width:auto;
|
||||
background-color:firebrick;
|
||||
}
|
||||
|
||||
.slot-wrapper{
|
||||
display:flex;
|
||||
height:3em;
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<range-slider class="slider" min="1" :max="maxSlots" step="1" v-model="slotSlider" v-on:input="assignEuclidean(slotSlider, pulseSlider)" ></range-slider>
|
||||
<input id="pulseSlider" v-model="maxSlots" />
|
||||
<range-slider class="slider" min="1" :max="slotSlider" step="1" v-model="pulseSlider" v-on:input ="assignEuclidean(slotSlider, pulseSlider)" ></range-slider>
|
||||
<input id="pulseSlider" value="3" v-model="assignBeat" />
|
||||
<input id="pulseSlider" value="3" />
|
||||
</div>
|
||||
<!---
|
||||
<div style="background-color:firebrick">
|
||||
|
|
52
espify.sh
Executable file
52
espify.sh
Executable file
|
@ -0,0 +1,52 @@
|
|||
#!/bin/bash
|
||||
|
||||
prefix="dist"
|
||||
flist="$(find $prefix -type f -name '*.js' -or -name 'index.html' -or -name 'favicon.ico' | sed -e 's/'$prefix'\/*//')"
|
||||
|
||||
get_var_name()
|
||||
{
|
||||
echo -e "static_$(echo -e $1 | tr -d '_' | tr '/.' '_')"
|
||||
}
|
||||
|
||||
cat <<EOF
|
||||
#include "gadgety.h"
|
||||
#include <ESP8266WebServer.h>
|
||||
|
||||
EOF
|
||||
|
||||
for i in $flist; do
|
||||
echo -e "unsigned char PROGMEM $(get_var_name $i)[] = {"
|
||||
gzip -c "$prefix/$i" | xxd -i -c 16
|
||||
echo -e "};\n"
|
||||
done
|
||||
|
||||
cat <<EOF
|
||||
static ESP8266WebServer *_server = 0;
|
||||
|
||||
#define SERVE_STATIC(p) static void serve_ ## p (void) { \\
|
||||
_server->sendHeader("Content-Encoding", "gzip"); \\
|
||||
_server->send_P(200, "text/html", (const char*)p, sizeof(p)); \\
|
||||
}
|
||||
|
||||
static void redirect_index(void)
|
||||
{
|
||||
_server->sendHeader("Location", "/");
|
||||
_server->send(301);
|
||||
}
|
||||
|
||||
EOF
|
||||
|
||||
for i in $flist; do
|
||||
echo -e "SERVE_STATIC($(get_var_name $i))"
|
||||
done
|
||||
|
||||
echo -e "\nvoid gadgety_static_init_server(ESP8266WebServer* server)\n{"
|
||||
echo -e " _server = server;"
|
||||
echo -e " server->onNotFound(redirect_index);"
|
||||
echo -e " server->on(\"/\", serve_static_index_html);"
|
||||
|
||||
for i in $flist; do
|
||||
echo -e " server->on(\"/$i\", serve_$(get_var_name $i));"
|
||||
done
|
||||
|
||||
echo -e "}"
|
Binary file not shown.
|
@ -21,6 +21,14 @@ module.exports = {
|
|||
** Build configuration
|
||||
*/
|
||||
build: {
|
||||
filenames: {
|
||||
css: 'common.css',
|
||||
manifest: 'manifest.js',
|
||||
vendor: 'common.js',
|
||||
app: 'app.js',
|
||||
chunk: '[name].js'
|
||||
},
|
||||
|
||||
/*
|
||||
** Run ESLint on save
|
||||
*/
|
||||
|
@ -36,4 +44,3 @@ module.exports = {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
<template>
|
||||
<div id="app">
|
||||
<h2 class="subtitle">
|
||||
<h2 id="titolone" class="subtitle" style="background:beige;position:absolute;bottom:0">
|
||||
Second attempt at building a web interface for ESP8266
|
||||
</h2>
|
||||
<sequencer></sequencer>
|
||||
<sequencer></sequencer>
|
||||
<sequencer></sequencer>
|
||||
<sequencer></sequencer>
|
||||
<div style="margin-top:1em;margin-bottom:1em;display:flex;width:100%;height:3em;background:#3333333;align-items:center;justify-content:center">
|
||||
<div>
|
||||
<div class="icon-button" style="flex:1 1 auto" v-on:click="addLine()">
|
||||
<img style="margin:auto;" src="~/assets/img/add.png">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-for="line in lines" :key='line.id'>
|
||||
<sequencer class="jsonSequencer" :id='line.id' :line='line'></sequencer>
|
||||
</div>
|
||||
<div class="icon-wrapper">
|
||||
<div class="icon-button">
|
||||
<img style="margin:auto;" src="~/assets/img/barrier.png">
|
||||
|
@ -20,9 +26,7 @@
|
|||
<div class="icon-button">
|
||||
<img style="margin:auto;" src="~/assets/img/bell.png">
|
||||
</div>
|
||||
<div class="icon-button">
|
||||
<img style="margin:auto;" src="~/assets/img/add.png">
|
||||
</div>
|
||||
<input type="submit" value="Send!" style="width:5em;height:2em;background:red;border:none;color:white;" v-on:click="getSequencerData()">
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -31,16 +35,55 @@
|
|||
import sequencer from '~/components/sequencer.vue'
|
||||
import sequencerDivided from '~/components/sequencerDivided.vue'
|
||||
import beatMenu from '~/components/beatMenu.vue'
|
||||
import moduleData from '~/assets/js/moduleData.json'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
lines: []
|
||||
// https://stackoverflow.com/questions/44869287/set-object-in-data-from-a-method-in-vue-js#44869373
|
||||
// creata object in data vue
|
||||
}
|
||||
},
|
||||
components: {
|
||||
sequencer,
|
||||
sequencerDivided,
|
||||
beatMenu
|
||||
},
|
||||
methods:
|
||||
{
|
||||
addLine: function (){
|
||||
this.lines.push({
|
||||
id: this.lines.length,
|
||||
slotSlider: 16,
|
||||
pulseSlider: 3,
|
||||
euclideanList: [],
|
||||
controlIsDisplayed: false });
|
||||
},
|
||||
getSequencerData: function(){
|
||||
var modelEsp = {
|
||||
'millis_per_slot': 500, // bpm = 60000 / millis_per_slot
|
||||
'lines': this.lines.map(function(line) {
|
||||
return line.euclideanList.reduce(function(acc, x) { return acc + x.toString(); }, '');
|
||||
})
|
||||
};
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', '/play.ws');
|
||||
|
||||
xhr.onreadystatechange = function () {
|
||||
if(xhr.readyState === 4 && xhr.status === 200) {
|
||||
//self.commits = JSON.parse(xhr.responseText);
|
||||
console.log("Recv", xhr.responseText);
|
||||
}
|
||||
};
|
||||
|
||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
xhr.send(JSON.stringify(modelEsp));
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.icon-button{
|
||||
display:flex;
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Loading…
Reference in a new issue