sort out order of operations for vue components
This commit is contained in:
parent
147e31d03c
commit
480e20a722
@ -8,6 +8,9 @@
|
||||
<h2>Todo List</h2>
|
||||
{% vue { component:"ListComp"} %}
|
||||
{% vue { component:"ListComp", props: { startlist: [{message:"Render Vue in Nunjucks"}, {message:"???"}, {message:"Profit!"}] } } %}
|
||||
{% vue { component:"RecordPlayer", props: { record: "https://hearsepileup.rip/music/last_time.mp3" } } %}
|
||||
{% vue { component:"RecordPlayer", props: { record: "https://hearsepileup.rip/music/generation_y.mp3" } } %}
|
||||
{% vue { component:"RecordPlayer", props: { record: "https://hearsepileup.rip/music/pretty_shiny_things.mp3" } } %}
|
||||
<section id="content" role="main" class="content-wrapper">
|
||||
{{content|safe}}
|
||||
</section>
|
||||
|
776
package-lock.json
generated
776
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
16
package.json
16
package.json
@ -14,7 +14,7 @@
|
||||
"devDependencies": {
|
||||
"@11ty/eleventy": "^0.8.3",
|
||||
"@babel/core": "^7.5.5",
|
||||
"@babel/node": "^7.5.0",
|
||||
"@babel/node": "^7.5.5",
|
||||
"@babel/plugin-transform-modules-commonjs": "^7.5.0",
|
||||
"@babel/preset-env": "^7.5.5",
|
||||
"autoprefixer": "^9.6.1",
|
||||
@ -25,24 +25,24 @@
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
"co": "^4.6.0",
|
||||
"compression": "^1.7.4",
|
||||
"css-loader": "^3.0.0",
|
||||
"css-loader": "^3.2.0",
|
||||
"debug": "^4.1.1",
|
||||
"file-loader": "^4.0.0",
|
||||
"file-loader": "^4.2.0",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"mini-css-extract-plugin": "^0.7.0",
|
||||
"mini-css-extract-plugin": "^0.8.0",
|
||||
"node-sass": "^4.12.0",
|
||||
"optimize-js-plugin": "0.0.4",
|
||||
"postcss-loader": "^3.0.0",
|
||||
"require-from-string": "^2.0.2",
|
||||
"sass-loader": "^7.1.0",
|
||||
"sass-loader": "^7.2.0",
|
||||
"strip-ansi": "^5.2.0",
|
||||
"style-loader": "^0.23.1",
|
||||
"style-loader": "^1.0.0",
|
||||
"tree-kill": "^1.2.1",
|
||||
"url-loader": "^2.0.1",
|
||||
"url-loader": "^2.1.0",
|
||||
"vue-loader": "^15.7.1",
|
||||
"vue-server-renderer": "^2.6.10",
|
||||
"vue-template-compiler": "^2.6.10",
|
||||
"webpack": "^4.35.3",
|
||||
"webpack": "^4.39.2",
|
||||
"webpack-assets-manifest": "^3.1.1",
|
||||
"webpack-cli": "^3.3.6"
|
||||
},
|
||||
|
4
serve.js
4
serve.js
@ -158,10 +158,10 @@ const build_site = debounce(
|
||||
200
|
||||
);
|
||||
|
||||
build_site();
|
||||
|
||||
const compiler = webpack(config(process.env.NODE_ENV));
|
||||
|
||||
compiler.watch({}, err => {
|
||||
sync.reload();
|
||||
});
|
||||
|
||||
build_site();
|
||||
|
461
src/js/components/RecordPlayer.vue
Normal file
461
src/js/components/RecordPlayer.vue
Normal file
@ -0,0 +1,461 @@
|
||||
<template lang="html">
|
||||
<div class="RecordPlayer" v-bind:data-record="recordUrl">
|
||||
<button class="toggle" v-on:click="togglePlay">
|
||||
<svg v-if="playing === false">
|
||||
<use :xlink:href="playIcon" />
|
||||
</svg>
|
||||
<svg v-else>
|
||||
<use :xlink:href="pauseIcon" />
|
||||
</svg>
|
||||
</button>
|
||||
<canvas
|
||||
class="disc"
|
||||
ref="disc"
|
||||
v-bind:width="canvasSize"
|
||||
v-bind:height="canvasSize"
|
||||
v-on:mousedown="beginScrubbing"
|
||||
/>
|
||||
<!-- <p class="devinfo">Scrubbing: {{ scrubbing }}</p> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ["record"],
|
||||
data: function(args) {
|
||||
let maxRecordSize = 320 - 40;
|
||||
let maxRecordInnerSize = 100;
|
||||
return {
|
||||
playing: false,
|
||||
scrubbing: false,
|
||||
playIcon: "#playbutton",
|
||||
pauseIcon: "#pausebutton",
|
||||
playPosition: 0,
|
||||
buffered: 0,
|
||||
mousePos: null,
|
||||
initialised: false,
|
||||
bassBoom: 1,
|
||||
canvasSize: 320,
|
||||
maxRecordSize,
|
||||
minRecordSize: maxRecordSize - maxRecordSize / 6,
|
||||
maxRecordInnerSize,
|
||||
recordInnerSize: maxRecordInnerSize,
|
||||
recordSize: maxRecordSize,
|
||||
eqBarCache: null,
|
||||
eqBarWidth: 0,
|
||||
eqBarRotation: 0,
|
||||
eqSampleSize: 2,
|
||||
recordUrl: this.record
|
||||
};
|
||||
},
|
||||
mounted: function() {
|
||||
this.audioElement = document.createElement("audio");
|
||||
this.audioElement.crossOrigin = 'anonymous';
|
||||
console.log(this.record);
|
||||
this.audioElement.src = this.record;
|
||||
let disc = this.$refs.disc;
|
||||
|
||||
this.eqBarCache = document.createElement("canvas");
|
||||
this.eqBarCacheWhite = document.createElement("canvas");
|
||||
// this.eqBarCache = this.$refs.cache;
|
||||
this.eqBarCache.width = 80;
|
||||
this.eqBarCache.height = disc.height / 2;
|
||||
this.eqBarCacheWhite.width = 80;
|
||||
this.eqBarCacheWhite.height = disc.height / 2;
|
||||
|
||||
this.discCtx = disc.getContext("2d");
|
||||
|
||||
this.drawUI();
|
||||
|
||||
this.audioElement.addEventListener("playing", () => {
|
||||
if (!this.initialised) {
|
||||
this.initialised = true;
|
||||
}
|
||||
if (!this.analyser) {
|
||||
this.audioCtx = new (window.AudioContext ||
|
||||
window.webkitAudioContext)();
|
||||
this.analyser = this.audioCtx.createAnalyser();
|
||||
this.source = this.audioCtx.createMediaStreamSource(
|
||||
this.audioElement.captureStream()
|
||||
);
|
||||
this.source.connect(this.analyser);
|
||||
|
||||
this.analyser.fftSize = 256;
|
||||
this.analyser.smoothingTimeConstant = 0.3;
|
||||
this.bufferLength = this.analyser.frequencyBinCount;
|
||||
this.dataArray = new Uint8Array(this.bufferLength);
|
||||
this.freqArray = new Uint8Array(this.bufferLength);
|
||||
|
||||
let segmentWidth =
|
||||
360 / (this.analyser.fftSize / (this.eqSampleSize * 2));
|
||||
|
||||
this.eqBarWidth = (segmentWidth / 5) * 3 * (Math.PI / 180);
|
||||
this.eqBarRotation = segmentWidth * (Math.PI / 180);
|
||||
|
||||
this.createBarData();
|
||||
} else {
|
||||
// let audioCtx = new (window.AudioContext || window.webkitAudioContext)();
|
||||
this.source = this.audioCtx.createMediaStreamSource(
|
||||
this.audioElement.captureStream()
|
||||
);
|
||||
this.source.connect(this.analyser);
|
||||
}
|
||||
});
|
||||
this.audioElement.addEventListener("ended", () => {
|
||||
this.playing = false;
|
||||
this.initialised = false;
|
||||
this.drawUI();
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
createBarData: function() {
|
||||
this.drawBar(this.eqBarCache, "rgb(0, 0, 0)");
|
||||
this.drawBar(this.eqBarCacheWhite, "rgb(255, 255, 255)");
|
||||
},
|
||||
drawBar: function(canvas, colour) {
|
||||
let ctx = canvas.getContext("2d");
|
||||
let disc = this.$refs.disc;
|
||||
|
||||
ctx.fillStyle = "rgba(0, 0, 0, 0.0)";
|
||||
ctx.clearRect(0, 0, ctx.width, ctx.height);
|
||||
|
||||
ctx.fillStyle = colour;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(0, this.eqBarCache.height);
|
||||
ctx.arc(
|
||||
0,
|
||||
disc.height / 2,
|
||||
disc.height / 2,
|
||||
0 - Math.PI / 2,
|
||||
this.eqBarWidth - Math.PI / 2
|
||||
// Math.PI * 2
|
||||
);
|
||||
// ctx.moveTo(0, this.eqBarCache.height);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
},
|
||||
draw: function() {
|
||||
if (this.playing || this.scrubbing) {
|
||||
let drawVisual = requestAnimationFrame(this.draw);
|
||||
}
|
||||
|
||||
let disc = this.$refs.disc;
|
||||
let ctx = this.discCtx;
|
||||
|
||||
ctx.clearRect(0, 0, disc.width, disc.height);
|
||||
|
||||
this.drawUI();
|
||||
|
||||
if (this.analyser) {
|
||||
this.runAnalysis();
|
||||
}
|
||||
},
|
||||
drawUI: function() {
|
||||
let ctx = this.discCtx;
|
||||
let disc = this.$refs.disc;
|
||||
|
||||
// Outer ring
|
||||
ctx.lineWidth = 3;
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle = "rgb(38, 38, 38)";
|
||||
ctx.arc(
|
||||
disc.width / 2,
|
||||
disc.height / 2,
|
||||
disc.width / 2 - 4,
|
||||
0,
|
||||
Math.PI * 2
|
||||
);
|
||||
ctx.closePath();
|
||||
ctx.stroke();
|
||||
|
||||
// Inner Ring
|
||||
ctx.beginPath();
|
||||
ctx.arc(disc.width / 2, disc.height / 2, 80 / 2, 0, Math.PI * 2);
|
||||
ctx.closePath();
|
||||
ctx.stroke();
|
||||
|
||||
if (this.initialised) {
|
||||
this.drawRecord();
|
||||
}
|
||||
},
|
||||
runAnalysis: function() {
|
||||
let ctx = this.discCtx;
|
||||
let disc = this.$refs.disc;
|
||||
this.analyser.getByteFrequencyData(this.dataArray);
|
||||
this.analyser.getByteTimeDomainData(this.freqArray);
|
||||
|
||||
let bassSample = this.dataArray.slice(this.dataArray.length / 4);
|
||||
let bassVolume =
|
||||
bassSample.reduce((accumulated, vol) => {
|
||||
return accumulated + vol;
|
||||
}, 0) /
|
||||
(this.dataArray.length / 4);
|
||||
|
||||
this.bassBoom = bassVolume / 255;
|
||||
|
||||
let variance = this.bassBoom * (this.maxRecordSize - this.minRecordSize);
|
||||
|
||||
this.recordSize = this.minRecordSize + variance;
|
||||
this.recordInnerSize = this.maxRecordInnerSize + variance;
|
||||
},
|
||||
drawRecord: function() {
|
||||
let ctx = this.discCtx;
|
||||
let disc = this.$refs.disc;
|
||||
|
||||
// White Disc
|
||||
ctx.fillStyle = "rgb(255, 255, 255)";
|
||||
ctx.beginPath();
|
||||
ctx.arc(
|
||||
disc.width / 2,
|
||||
disc.height / 2,
|
||||
this.recordSize / 2,
|
||||
0,
|
||||
Math.PI * 2,
|
||||
false
|
||||
);
|
||||
ctx.arc(
|
||||
disc.width / 2,
|
||||
disc.height / 2,
|
||||
this.recordInnerSize / 2,
|
||||
0,
|
||||
Math.PI * 2,
|
||||
true
|
||||
);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
|
||||
if (this.audioElement.buffered.length > 0) {
|
||||
let buffered = this.audioElement.buffered;
|
||||
this.buffered =
|
||||
(this.audioElement.buffered.end(
|
||||
this.audioElement.buffered.length - 1
|
||||
) /
|
||||
this.audioElement.duration) *
|
||||
100;
|
||||
}
|
||||
|
||||
if (this.audioElement.duration) {
|
||||
this.playPosition =
|
||||
(this.audioElement.currentTime / this.audioElement.duration) * 100;
|
||||
}
|
||||
|
||||
// Buffered Ring
|
||||
this.drawProgressBar("rgb(200, 200, 200)", this.buffered);
|
||||
|
||||
// Playhead Position
|
||||
this.drawProgressBar("rgb(0, 0, 0)", this.playPosition);
|
||||
|
||||
this.drawEqualizerBars();
|
||||
},
|
||||
drawProgressBar: function(color, percentage) {
|
||||
let ctx = this.discCtx;
|
||||
let disc = this.$refs.disc;
|
||||
let startPos = Math.PI * 2 - Math.PI / 2;
|
||||
let progressPosition = startPos + ((Math.PI * 2) / 100) * percentage;
|
||||
|
||||
ctx.fillStyle = color;
|
||||
ctx.beginPath();
|
||||
ctx.arc(
|
||||
disc.width / 2,
|
||||
disc.height / 2,
|
||||
this.recordSize / 2,
|
||||
progressPosition,
|
||||
startPos,
|
||||
true
|
||||
);
|
||||
ctx.lineTo(disc.width / 2, disc.height / 2 - 11 / 2);
|
||||
ctx.arc(
|
||||
disc.width / 2,
|
||||
disc.height / 2,
|
||||
this.recordInnerSize / 2,
|
||||
startPos,
|
||||
progressPosition,
|
||||
false
|
||||
);
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
},
|
||||
drawEqualizerBars() {
|
||||
let ctx = this.discCtx;
|
||||
let disc = this.$refs.disc;
|
||||
let dataPoints = [];
|
||||
|
||||
let rotateAmount = this.eqBarRotation;
|
||||
// console.log(this.freqArray.length / this.eqSampleSize);
|
||||
|
||||
for (let i = 0; i < this.freqArray.length; i += this.eqSampleSize) {
|
||||
dataPoints.push(this.freqArray.slice(i, i + this.eqSampleSize));
|
||||
}
|
||||
|
||||
dataPoints.forEach((freqData, i) => {
|
||||
let mean =
|
||||
freqData.reduce((dataPoint, total) => {
|
||||
return total + dataPoint;
|
||||
}, 0) / freqData.length;
|
||||
let multiplier = (mean - 126) / 100;
|
||||
let ringWidth = this.recordSize - this.recordInnerSize;
|
||||
|
||||
let barSize = (this.recordInnerSize + ringWidth * multiplier) / 2;
|
||||
|
||||
barSize = barSize >= 0 ? barSize : 0;
|
||||
|
||||
// if (i === 0) {
|
||||
// console.log(barSize, this.recordInnerSize);
|
||||
// }
|
||||
|
||||
ctx.save();
|
||||
ctx.beginPath();
|
||||
// if (barSize < this.recordInnerSize / 2) {
|
||||
ctx.arc(
|
||||
disc.width / 2,
|
||||
disc.height / 2,
|
||||
this.recordInnerSize / 2,
|
||||
0,
|
||||
Math.PI * 2,
|
||||
barSize <= this.recordInnerSize / 2
|
||||
);
|
||||
// }
|
||||
|
||||
// if (i === 3) {
|
||||
// console.log(
|
||||
// this.playPosition,
|
||||
// i / dataPoints.length * 100,
|
||||
// this.playPosition < i / dataPoints.length * 100
|
||||
// );
|
||||
// }
|
||||
|
||||
ctx.arc(
|
||||
disc.width / 2,
|
||||
disc.height / 2,
|
||||
barSize,
|
||||
0,
|
||||
Math.PI * 2,
|
||||
barSize > this.recordInnerSize / 2
|
||||
);
|
||||
ctx.closePath();
|
||||
ctx.translate(disc.width / 2, disc.height / 2);
|
||||
ctx.rotate(rotateAmount * i);
|
||||
ctx.clip();
|
||||
ctx.drawImage(
|
||||
barSize > this.recordInnerSize / 2 &&
|
||||
this.playPosition < (i / dataPoints.length) * 100
|
||||
? this.eqBarCache
|
||||
: this.eqBarCacheWhite,
|
||||
/*disc.width / 2*/ 0,
|
||||
-(disc.height / 2)
|
||||
);
|
||||
ctx.rotate(-(rotateAmount * i));
|
||||
ctx.translate(-(disc.width / 2), -(disc.height / 2));
|
||||
ctx.restore();
|
||||
});
|
||||
},
|
||||
togglePlay: function() {
|
||||
if (!this.playing) {
|
||||
this.audioElement.play();
|
||||
this.playing = !this.playing;
|
||||
this.draw();
|
||||
} else {
|
||||
this.audioElement.pause();
|
||||
this.playing = !this.playing;
|
||||
}
|
||||
},
|
||||
beginScrubbing: function(e) {
|
||||
if (this.initialised) {
|
||||
this.scrubbing = true;
|
||||
this.draw();
|
||||
|
||||
window.addEventListener("mouseup", this.finishScrubbing);
|
||||
window.addEventListener("mousemove", this.scrub);
|
||||
|
||||
this.scrub(e);
|
||||
|
||||
if (e.stopPropagation) e.stopPropagation();
|
||||
if (e.preventDefault) e.preventDefault();
|
||||
e.cancelBubble = true;
|
||||
e.returnValue = false;
|
||||
return false;
|
||||
}
|
||||
},
|
||||
scrub: function(e) {
|
||||
let discPos = this.$refs.disc.getBoundingClientRect();
|
||||
let centre = {
|
||||
x: discPos.x + discPos.width / 2,
|
||||
y: discPos.y + discPos.height / 2
|
||||
};
|
||||
let mousePos = { x: e.clientX, y: e.clientY };
|
||||
|
||||
let angle =
|
||||
Math.atan2(centre.y - mousePos.y, centre.x - mousePos.x) +
|
||||
Math.PI +
|
||||
Math.PI / 2;
|
||||
|
||||
angle = angle > Math.PI * 2 ? angle - Math.PI * 2 : angle;
|
||||
|
||||
let position = angle / (Math.PI * 2);
|
||||
|
||||
this.audioElement.currentTime = this.audioElement.duration * position;
|
||||
},
|
||||
finishScrubbing: function(e) {
|
||||
this.scrubbing = false;
|
||||
window.removeEventListener("mouseup", this.finishScrubbing);
|
||||
window.removeEventListener("mousemove", this.scrub);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// @import "~styles/_vars.scss";
|
||||
|
||||
.RecordPlayer {
|
||||
position: relative;
|
||||
width: 160px;
|
||||
height: 160px;
|
||||
}
|
||||
|
||||
.disc {
|
||||
width: 160px;
|
||||
height: 160px;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.toggle {
|
||||
position: absolute;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
top: 61px;
|
||||
left: 61px;
|
||||
border: 0;
|
||||
background: none;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(#191919, #000);
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
background: linear-gradient(#000, #191919);
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: white;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
display: block;
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.devinfo {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
width: 100%;
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
@ -1,6 +1,7 @@
|
||||
import Vue from "vue";
|
||||
import HelloWorld from "./components/HelloWorld.vue";
|
||||
import ListComp from "./components/ListComp.vue";
|
||||
import RecordPlayer from "./components/RecordPlayer.vue";
|
||||
|
||||
Array.prototype.forEach.call(document.querySelectorAll(".HelloWorld"), function(
|
||||
elem
|
||||
@ -17,3 +18,11 @@ Array.prototype.forEach.call(document.querySelectorAll(".ListComp"), function(
|
||||
render: h => h(ListComp, { props: { startlist: elem.dataset.startlist } })
|
||||
}).$mount(elem);
|
||||
});
|
||||
|
||||
Array.prototype.forEach.call(document.querySelectorAll(".RecordPlayer"), function(
|
||||
elem
|
||||
) {
|
||||
new Vue({
|
||||
render: h => h(RecordPlayer, { props: { record: elem.dataset.record } })
|
||||
}).$mount(elem);
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user