<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
</head>
<body>
<h1>Hello Plunker!</h1>
<div id="app">
<form>
<button type="button" @click="start">Start</button>
<button type="button" @click="stop">Stop</button>
<div class="scope-type">
<h3>描画タイプ</h3>
<label><input type="radio" value="svg" v-model="scopeType">SVG</label>
<label><input type="radio" value="canvas" v-model="scopeType">Canvas</label>
</div>
</form>
<div class="oscilloscopes">
<svg
v-if="scopeType === 'svg'"
ref="scope"
:width="size.width"
:height="size.height"
xmlns="http://www.w3.org/2000/svg"
baseProfile="full"
>
<path :d="svg.path" stroke="#00F23E" stroke-width="3" fill="none"></path>
</svg>
<canvas
v-if="scopeType === 'canvas'"
ref="scope"
:width="size.width"
:height="size.height">
</canvas>
</div>
<div class="fps-checker">
<span>{{ fps }}fps</span>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
new Vue({
el: '#app',
data() {
return {
size: {
width: 400,
height: 256
},
scopeType: 'svg',
svg: {
path: ''
},
canvas: {
ctx: null
},
audio: {
ctx: new AudioContext(),
osc: null,
analyser: null,
running: false
},
fps: 0
}
},
methods: {
start() {
this.audio.running = true;
this.audio.analyser = this.audio.ctx.createAnalyser();
this.audio.analyser.connect(this.audio.ctx.destination);
this.audio.analyser.fftSize = 128;
this.audio.osc = this.audio.ctx.createOscillator();
this.audio.osc.connect(this.audio.analyser);
this.audio.osc.start();
switch (this.scopeType)
{
case 'svg':
this.drawSVG();
break;
case 'canvas':
this.drawCanvas();
break;
}
},
stop() {
this.audio.osc.stop();
this.audio.running = false;
},
drawSVG() {
const bufferLength = this.audio.analyser.frequencyBinCount;
const update = () => {
let data = new Uint8Array(bufferLength);
this.audio.analyser.getByteTimeDomainData(data);
let d = 'M';
data.forEach((p, i) => {
d += `${i * (this.size.width / bufferLength)} ${p},`;
});
this.svg.path = d;
if (this.audio.running)
{
window.requestAnimationFrame(update.bind(this));
}
};
window.requestAnimationFrame(update.bind(this));
},
drawCanvas() {
const ctx = this.$refs.scope.getContext('2d');
ctx.lineWidth = 3;
ctx.strokeStyle = '#00F23E';
const bufferLength = this.audio.analyser.frequencyBinCount
const update = () => {
ctx.clearRect(0, 0, this.size.width, this.size.height);
ctx.save();
ctx.moveTo(0, this.size.height / 2);
ctx.beginPath();
let data = new Uint8Array(bufferLength);
this.audio.analyser.getByteTimeDomainData(data);
data.forEach((p, i) => {
ctx.lineTo(i * (this.size.width / bufferLength), p);
});
ctx.stroke();
ctx.restore();
if (this.audio.running)
{
window.requestAnimationFrame(update.bind(this));
}
};
window.requestAnimationFrame(update.bind(this));
}
}
});
svg {
background-color: #333333;
}
canvas {
background-color: #333333;
}