I have to create a animation Like Google.com Dekstop Mic shows (i.e. scaling of the mic border according to the loudness of voice). I have used the Web Speech API with reference from here (MDN) which shows how we can change the background colour of the webpage using our voice, it work's fine but I want to add Animation Like Google's site( mentioned above).I have searched a lot to find a way to achieve this animation but I was unable to find this. So I am asking here as this is the best place where I can get my answer :) Thanks a lot in advance for helping me out with this.
I'm not expert in this area but I followed the example in MDN and here is the result.
Beside the setup, the key point here is analyser.getByteFrequencyData which gives us the decibel levels.
In order to simplify the code, I took the highest decibel level in the array (Math.max.apply(null, dataArray)) but you can fine tuning it by average or any other calculation you like.
Demo
let audioCtx = new (window.AudioContext || window.webkitAudioContext)();
let distortion = audioCtx.createWaveShaper();
let gainNode = audioCtx.createGain();
let biquadFilter = audioCtx.createBiquadFilter();
let analyser = audioCtx.createAnalyser();
analyser.minDecibels = -90;
analyser.maxDecibels = -10;
analyser.fftSize = 256;
const mic = document.querySelector('.mic');
let isListening = false;
let tracks = [];
if (!navigator.mediaDevices.getUserMedia) {
alert('getUserMedia not supported on your browser!');
}
mic.addEventListener('click', async () => {
if (!isListening) {
try {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
isListening = true;
tracks = stream.getTracks();
source = audioCtx.createMediaStreamSource(stream);
source.connect(distortion);
distortion.connect(biquadFilter);
biquadFilter.connect(gainNode);
gainNode.connect(analyser);
analyser.connect(audioCtx.destination);
requestAnimationFrame(function log() {
let bufferLength = analyser.frequencyBinCount;
let dataArray = new Uint8Array(bufferLength);
analyser.getByteFrequencyData(dataArray);
const level = Math.max.apply(null, dataArray);
document.querySelector('#level span').textContent = level;
mic.style.setProperty('--border', `${level / 5}px`);
requestAnimationFrame(log);
});
} catch (err) {
console.log('The following gUM error occured: ' + err);
}
} else {
isListening = false;
tracks.forEach((track) => {
track.stop();
});
}
});
body {
margin: 0;
height: 100vh;
position: relative;
}
.content {
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 20px;
}
.mic {
background: #fff;
width: 50px;
height: 50px;
border: 1px solid #eee;
border-radius: 100%;
bottom: 0;
box-shadow: 0 2px 5px var(--border) rgb(0 0 0 / 10%);
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
}
<html>
<head>
<meta charset="UTF-8" />
<link rel="stylesheet" type="text/css" href="styles.css" />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"
integrity="sha512-Fo3rlrZj/k7ujTnHg4CGR2D7kSs0v4LLanw2qksYuRlEzO+tcaEPQogQ0KaoGN26/zrn20ImR1DfuLWnOo7aBA=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
</head>
<body>
<div class="content">
<div class="mic">
<i class="fas fa-microphone"></i>
</div>
<div id="level">Level: <span></span></div>
</div>
<script src="script.js"></script>
</body>
</html>
Related
I am trying to render the key points to a canvas that I can getting from Blaze Pose, but I can't seem to get them drawing the canvas. I know the x and y for each key point and being retrieved but I can't get them showing up on the canvas. I have tried changing the styling but no luck so far. Thanks for the help.
const video = document.getElementById('webcam');
const canvas = document.getElementById('output')
const liveView = document.getElementById('liveView');
const demosSection = document.getElementById('demos');
const enableWebcamButton = document.getElementById('webcamButton');
const ctx = canvas.getContext("2d");
let poses;
function getUserMediaSupported() {
return !!(navigator.mediaDevices &&
navigator.mediaDevices.getUserMedia);
}
if (getUserMediaSupported()) {
enableWebcamButton.addEventListener('click', enableCam);
} else {
console.warn('getUserMedia() is not supported by your browser');
}
// Enable the live webcam view and start classification.
function enableCam(event) {
if (!model) {
return;
}
// Hide the button once clicked.
event.target.classList.add('removed');
// getUsermedia parameters to force video but not audio.
const constraints = {
video: true
};
document.getElementById('output').style.zIndex = "6";
// Activate the webcam stream.
navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
video.srcObject = stream;
video.addEventListener('loadeddata', predictWebcam);
});
}
async function predictWebcam() {
const videoHeight = video.videoHeight;
const videoWidth = video.videoWidth;
video.width = videoWidth;
video.height = videoHeight;
canvas.width = videoWidth;
canvas.height = videoHeight;
poses = await detector.estimatePoses(video)
//ctx.drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
if(poses && poses.length > 0){
for(const pose of poses){
if(pose.keypoints != null){
drawKeypoints(pose.keypoints);
}
}
}
window.requestAnimationFrame(predictWebcam);
}
function drawKeypoints(keypoints){
for(let i = 0; i < keypoints.length; i++){
drawKeypoint(keypoints[i]);
}
}
function drawKeypoint(keypoint){
ctx.fillStyle = 'Orange';
ctx.strokeStyle = 'Green';
ctx.lineWidth = 2;
const radius = 4;
const circle = new Path2D();
circle.arc(keypoint.x, keypoint.y, radius, 0, 2 * Math.PI)
ctx.fill(circle)
ctx.stroke(circle)
}
// Store the resulting model in the global scope of our app.
let model = undefined;
let detector = undefined;
// Before we can use BlazePose class we must wait for it to finish
async function loadModel(){
model = poseDetection.SupportedModels.BlazePose;
const detectorConfig = {
runtime: 'tfjs',
enableSmoothing: true,
modelType: 'full'
};
detector = await poseDetection.createDetector(model, detectorConfig);
demosSection.classList.remove('invisible');
}
loadModel();
<!DOCTYPE html>
<html lang="en">
<head>
<title>Measuring App</title>
<meta charset="utf-8">
<!-- Import the webpage's stylesheet -->
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Measuring App</h1>
<p>Wait for the model to load before clicking the button to enable the webcam - at which point it will become visible to use.</p>
<section id="demos" class="invisible">
<div id="liveView" class="camView">
<button id="webcamButton">Enable Webcam</button>
<canvas id="output"></canvas>
<video id="webcam" autoplay muted width="640" height="480"></video>
</div>
</section>
<!-- Import TensorFlow.js library -->
<script src="https://cdn.jsdelivr.net/npm/#tensorflow/tfjs/dist/tf.min.js" type="text/javascript"></script>
<!-- Load the coco-ssd model to use to recognize things in images -->
<script src="https://cdn.jsdelivr.net/npm/#tensorflow-models/pose-detection"></script>
<!-- Import the page's JavaScript to do some stuff -->
<script src="script.js" defer></script>
</body>
</html>
body {
font-family: helvetica, arial, sans-serif;
margin: 2em;
color: #3D3D3D;
}
h1 {
font-style: italic;
color: #FF6F00;
}
video {
display: block;
}
section {
opacity: 1;
transition: opacity 500ms ease-in-out;
}
.removed {
display: none;
z-index: -10;
}
.invisible {
opacity: 0.2;
}
.camView {
position: relative;
float: left;
width: calc(100% - 20px);
margin: 10px;
cursor: pointer;
}
.camView p {
position: absolute;
padding: 5px;
background-color: rgba(255, 111, 0, 0.85);
color: #FFF;
border: 1px dashed rgba(255, 255, 255, 0.7);
z-index: 1;
font-size: 12px;
}
#output {
position: absolute;
z-index: -100;
top: 0;
bottom: 0;
left: 0;
}
I created this color guessing game from scratch using HTML, CSS and JS. You're given a random RGB value and you guess which out of three given colors is the correct one. Now I want to take it a step higher by adding a scoreboard and score (Which I'm not sure how to do at all) and a full-screen congratulation message when you guess the color right. I've tried doing that but the animation doesn't seem to work.
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="style.css">
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1 class="text-centered" id="main-h1">Guess The Color!</h1>
<h2 class="text-centered" id="colorguess"></h2>
<p id="score">
</p>
<div class="box-container">
<div class="box">
</div>
<div class="box">
</div>
<div class="box">
</div>
</div>
<div id="bravo">
<p id="bravo-text">
BRAVO
</p>
</div>
</body>
<script src="script.js"></script>
</html>
CSS
*{
box-sizing: border-box;
}
body{
font-family: arial;
background-color: #1c1874;
color: rgb(105, 105, 139);
color: #fff;
}
.text-centered{
text-align: center;
text-shadow: 0px 2px 2px rgba(150, 150, 150, 1);
}
.box-container{
padding: 200px;
align-self: center;
display: flex;
flex-direction: row;
justify-content:space-evenly;
}
.box{
width: 200px;
height: 200px;
border-radius: 20px;
cursor: pointer;
border:5px solid #ffffff;
}
#score{
font-weight: 500;
font-size: 2em;
position: fixed;
top: 5%;
left: 5%;
}
#score::before {
content: "Score: ";
}
#bravo{
position: fixed;
display: none;
opacity: 0;
top: 0;
left: 0;
width: 100%;
height: 100%;
margin: 0;
text-align: center;
font-size: 5em;
background-color: rgba(4, 8, 97, 0.69);
}
#bravo-text{
flex: 0 0 120px;
text-shadow: 0px 2px 2px rgba(150, 150, 150, 1);
}
JS
function getrandomcolor(){
var r = Math.floor(Math.random() * 256);
var g = Math.floor(Math.random() * 256);
var b = Math.floor(Math.random() * 256);
rgb = "rgb("+r+", "+g+", "+b+")";
return rgb;
}
function gamestart(){
var mainh1 = document.getElementById('main-h1');
mainh1.innerHTML = "Guess the color!";
rgbvaluetrue = getrandomcolor();
var rgb = document.getElementById('colorguess');
rgb.innerHTML = rgbvaluetrue;
var body = document.getElementsByTagName('body');
var box = document.getElementsByClassName('box');
var scoreboard= document.getElementById('score');
var score = 0;
function displaybravo(element){
var op= 0;
var timer = setInterval(function () {
if (op >= 1){
clearInterval(timer);
}
if(op>=0.1){
element.style.display = "flex";
element.style.flexDirection = "column";
element.style.justifyContent = "center";
element.style.alignItems="center";
}
element.style.opacity = op;
element.style.filter = 'alpha(opacity=' + op * 100 + ")";
op += op * 0.1;
}, 10);
}
for(var i=0;i<box.length;i++){
box[i].style.backgroundColor = getrandomcolor();
}
//here I am trying to assign the initial rgb value to one of the divs randomly
var rand = Math.floor(Math.random() * box.length);
box[rand].style.backgroundColor = rgbvaluetrue;
//here I check if the div you clicked on is correct
function markSelection() {
if(this.style.backgroundColor == rgbvaluetrue) {
mainh1.innerHTML="BRAVO";
setTimeout(function() {
var brv = document.getElementById('bravo');
displaybravo(brv);
gamestart(); }, 2000);
} else {
gamestart();
}
}
for(var i=0;i<box.length;i++){
box[i].onclick = markSelection;
}
scoreboard.innerHTML=score;
}
gamestart();
I reviewed your game and made some changes to the code based on what stood out to me. There were a few bugs that were important to correct, and many things I changed purely for readability / preference.
I tend to avoid directly using timeouts. Promises are a good way to control the order of things in javascript. This game could likely benefit from OOP to make the logic more organized, but I didn't want to return you something that was completely unrecognizable. You are welcome to take this to code review for a more complete refactoring.
The first issue that I noticed is that your setInterval never resolves with the logic implemented. Because it never resolves, every time you attempted to show the bravo message, it would start an interval at 10 ms, and they would stack on top of eachother. This quickly would become an issue, potentially even breaking your page. Instead of attempting to redesign your interval logic, I decided to use the css transition attribute to handle the Bravo message, and I threw in a keyframe animation so you could see how to add other effects without javascript. Instead of having to write logic in js and preform resource expensive operations, I can leave the animation to css. Now js just needs to add and remove the hidden class.
I also wrote a helper function wait at the top of the js, and made functions with waiting async so I could use the await keyword instead of nesting my code inside timeouts. This is more readable in my own opinion.
To add a score, I moved the score variable above the gameStart function. This way each time the game restarts, the score is not affected. Then I just had to increment the score variable whenever a correct answer is given, and change the text in the dom.
One bug I noticed was that the correct answer could have been clicked several times, and the points would have increased, because the event listener was still active after the answer was submitted. To handle this, I changed the way the event listener was applied. Instead of using element.onclick =, I opted for el.addEventListener("click", . This allowed me to use .removeEventListener once the answer was given, and only reapply the event listener once the next round started. I also added a wait for incorrect answers, and some text when the wrong answer was given.
Other more cosmetic changes include using a helper function $ to make grabbing elements easier, and changing .innerHTML to .innerText to more clearly show intent / prevent potential bugs.
I didn't correct it in this code, but it's worth mentioning variable names in javascript are usually camel case. i.e. instead of getrandomcolor it would be getRandomColor
If you have any questions about my code, please ask 👍
const wait = t => new Promise(r => setTimeout(r, t));
const $ = (str, dom = document) => [...dom.querySelectorAll(str)];
function getrandomcolor(){
const random255 = () => Math.floor(Math.random() * 256);
const [r, g, b] = Array.from({length: 3}, random255);
return "rgb(" + r + ", " + g + ", " + b + ")";
}
let scoreboard = $('#score')[0];
let score = 0;
function gamestart(){
var mainh1 = $('#main-h1')[0];
mainh1.innerText = "Guess the color!";
rgbvaluetrue = getrandomcolor();
var rgb = $('#colorguess')[0];
rgb.innerText = rgbvaluetrue;
var body = document.body;
var allBoxes = $('.box');
async function displaybravo(element){
element.classList.remove("hidden");
await wait(2000);
element.classList.add("hidden");
await wait(1000);
}
for (var i=0; i<allBoxes.length; i++) {
allBoxes[i].style.backgroundColor = getrandomcolor();
}
var randomBoxIndex = Math.floor(Math.random() * allBoxes.length);
allBoxes[randomBoxIndex].style.backgroundColor = rgbvaluetrue;
async function markSelection() {
allBoxes.forEach(box => box.removeEventListener("click", markSelection));
if (this.style.backgroundColor == rgbvaluetrue) {
score++;
scoreboard.innerText = score;
mainh1.innerText = "BRAVO";
var brv = $('#bravo')[0];
await displaybravo(brv);
gamestart();
} else {
mainh1.innerText = "NOPE!";
await wait(1000);
gamestart();
}
}
allBoxes.forEach(box => box.addEventListener("click", markSelection));
scoreboard.innerHTML = score;
}
gamestart();
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: arial;
background-color: #1c1874;
color: rgb(105, 105, 139);
color: #fff;
}
.text-centered{
text-align: center;
text-shadow: 0px 2px 2px rgba(150, 150, 150, 1);
}
.box-container{
padding: 200px;
align-self: center;
display: flex;
flex-direction: row;
justify-content:space-evenly;
}
.box{
width: 200px;
height: 200px;
border-radius: 20px;
cursor: pointer;
border:5px solid #ffffff;
}
#score{
font-weight: 500;
font-size: 2em;
position: fixed;
top: 5%;
left: 5%;
}
#score::before {
content: "Score: ";
}
#bravo {
overflow: hidden;
position: fixed;
inset: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100%; /*needed to transition to / from*/
transition: height 2s;
}
#bravo.hidden {
height: 0;
}
#bravo-text {
font-size: 5rem;
font-weight: bold;
color: black;
animation: glow 1s ease-in-out infinite alternate;
}
#keyframes glow {
from {
text-shadow:
0 0 5px #fff,
0 0 10px #fff,
0 0 15px #e60073,
0 0 20px #e60073,
0 0 25px #e60073,
0 0 30px #e60073,
0 0 35px #e60073;
}
to {
text-shadow:
0 0 10px #fff,
0 0 20px #ff4da6,
0 0 30px #ff4da6,
0 0 40px #ff4da6,
0 0 50px #ff4da6,
0 0 60px #ff4da6,
0 0 70px #ff4da6;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="main.css">
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script defer src="main.js"></script>
</head>
<body>
<h1 class="text-centered" id="main-h1">Guess The Color!</h1>
<h2 class="text-centered" id="colorguess"></h2>
<p id="score">
</p>
<div class="box-container">
<div class="box">
</div>
<div class="box">
</div>
<div class="box">
</div>
</div>
<div id="bravo" class="hidden flexCenter">
<p id="bravo-text" class="flexCenter">
BRAVO
</p>
</div>
</body>
</html>
I want to make an input where it can be automatically filled in after scanning a QR or barcode scanner using a webcam or phone cam.
for the script I imagined something like this
<video autoplay = "true" id = "video-webcam">
</video>
<input type = "text" id = "scanresult">
<script>
external or internal script for scan qr or barcode. save result in variable = result
html DOM getElementById ('scanresult'). value (result);
</script>
I hope anyone can give me suggestions or feedback for my problem.
Thank you
Before it thank you for JaromandaX,
i have found script for barcode scanner on Html5 using webcam.
this is my index.html
<!DOCTYPE html>
<html>
<head>
<title>QR Code Scanner</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;" />
<link rel="stylesheet" href="style.css" />
<script src="https://rawgit.com/sitepoint-editors/jsqrcode/master/src/qr_packed.js"></script>
</head>
<body>
<div id="container">
<h1>QR Code Scanner</h1>
<a id="btn-scan-qr">
<img src="https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2017/07/1499401426qr_icon.svg">
<a/>
<canvas hidden="" id="qr-canvas"></canvas>
<div id="qr-result" hidden="">
<b>Data:</b> <span id="outputData"></span>
</div>
</div>
<script src="qrCodeScanner.js"></script>
</body>
</html>
qsCodeScanner.js
//const qrcode = window.qrcode;
const video = document.createElement("video");
const canvasElement = document.getElementById("qr-canvas");
const canvas = canvasElement.getContext("2d");
const qrResult = document.getElementById("qr-result");
const outputData = document.getElementById("outputData");
const btnScanQR = document.getElementById("btn-scan-qr");
let scanning = false;
qrcode.callback = res => {
if (res) {
outputData.innerText = res;
scanning = false;
video.srcObject.getTracks().forEach(track => {
track.stop();
});
qrResult.hidden = false;
canvasElement.hidden = true;
btnScanQR.hidden = false;
}
};
btnScanQR.onclick = () => {
navigator.mediaDevices
.getUserMedia({ video: { facingMode: "environment" } })
.then(function(stream) {
scanning = true;
qrResult.hidden = true;
btnScanQR.hidden = true;
canvasElement.hidden = false;
video.setAttribute("playsinline", true); // required to tell iOS safari we don't want fullscreen
video.srcObject = stream;
video.play();
tick();
scan();
});
};
function tick() {
canvasElement.height = video.videoHeight;
canvasElement.width = video.videoWidth;
canvas.drawImage(video, 0, 0, canvasElement.width, canvasElement.height);
scanning && requestAnimationFrame(tick);
}
function scan() {
try {
qrcode.decode();
} catch (e) {
setTimeout(scan, 300);
}
}
style.css
html {
height: 100%;
}
body {
font-family: sans-serif;
padding: 0 10px;
height: 100%;
background: black;
margin: 0;
}
h1 {
color: white;
margin: 0;
padding: 15px;
}
#container {
text-align: center;
margin: 0;
}
#qr-canvas {
margin: auto;
width: calc(100% - 20px);
max-width: 400px;
}
#btn-scan-qr {
cursor: pointer;
}
#btn-scan-qr img {
height: 10em;
padding: 15px;
margin: 15px;
background: white;
}
#qr-result {
font-size: 1.2em;
margin: 20px auto;
padding: 20px;
max-width: 700px;
background-color: white;
}
There are lots of better libraries out there for doing this, but I'd personally recommend QrScanner because of its simplicity and intuitiveness.
Your live QrCode Scanner would be like this...
scanner.html
<div id="holder">
<h3>Scan QR Code from Camera</h3>
<div class="make">
<video id="scan"></video>
</div>
<div>
<input type = "text" id = "scanresult"><br>
<button id="start">Start</button>
<button id="stop">Stop</button>
</div>
</div>
Then add a little CSS as:
style.css
#holder{
width: 30%;
margin:auto;
}
#holder .make {
width: 99%;
height: 30vh;
margin-bottom: 15px;
text-align: center;
}
video {
width: 99%;
margin:auto;
}
Then add your QrScanner code as:
<script type="module">
import QrScanner from "/path/to/qr-scanner.min.js";
QrScanner.WORKER_PATH = "/path/to/qr-scanner-worker.min.js";
// Scanner Object
const scanner = new QrScanner(
document.getElementById("scan"),
function(result){
document.getElementById("scanresult").value = result;
}
);
document.getElementById("start").onclick = e => scanner.start();
document.getElementById("stop").onclick = e => scanner.stop();
</script>
Then connect your camera and click start button...
I have simple animation created using create js and ffmpegserver.js.
ffmpegserver.js.
This is a simple node server and library that sends canvas frames to the server and uses FFmpeg to compress the video. It can be used standalone or with CCapture.js.
Here is repo: video rendering demo.
on folder public, I have demos eg test3.html and test3.js
Test3.html
<!DOCTYPE html>
<html>
<head>
<title>TweenJS: Simple Tween Demo</title>
<style>
canvas {
border: 1px solid #08bf31;
justify-content: center;
display: flex;
align-items: center;
margin: 0px auto;
margin-bottom: 40px;
}
a {
width: 150px;
height: 45px;
background: red;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
border-radius: 300px;
color: white;
}
#container{
flex-direction: column;
justify-content: center;
display: flex;
align-items: center;
margin: 0px auto;
}
#progress{
margin: 30px;
}
#preview{
margin: 40px;
width: 150px;
height: 45px;
background: deepskyblue;
color: white;
border: none;
border-radius: 300px;
}
</style>
</head>
<body onload="init();">
<div>
<div id="container">
<h1>Simple Tween Demo</h1>
<canvas id="testCanvas" width="500" height="400"></canvas>
<div id="progress"></div>
</div>
</div>
<script src="http://localhost:8081/ffmpegserver/CCapture.js"></script>
<script src="http://localhost:8081/ffmpegserver/ffmpegserver.js"></script>
<script src="https://code.createjs.com/1.0.0/createjs.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/17.2.0/Tween.js"></script>
<script src="test3.js"></script>
</body>
</html>
Test3.js
/* eslint-disable eol-last */
/* eslint-disable no-undef */
/* eslint-disable quotes */
var canvas, stage;
function init() {
var framesPerSecond = 60;
var numFrames = framesPerSecond * 5; // a 5 second 60fps video
var frameNum = 0;
var progressElem = document.getElementById("progress");
var progressNode = document.createTextNode("");
progressElem.appendChild(progressNode);
function onProgress(progress) {
progressNode.nodeValue = (progress * 100).toFixed(1) + "%";
}
function showVideoLink(url, size) {
size = size ? (" [size: " + (size / 1024 / 1024).toFixed(1) + "meg]") : " [unknown size]";
var a = document.createElement("a");
a.href = url;
var filename = url;
var slashNdx = filename.lastIndexOf("/");
if (slashNdx >= 0) {
filename = filename.substr(slashNdx + 1);
}
a.download = filename;
a.appendChild(document.createTextNode("Download"));
var container = document.getElementById("container").insertBefore(a, progressElem);
}
var capturer = new CCapture( {
format: 'ffmpegserver',
//workersPath: "3rdparty/",
//format: 'gif',
//verbose: true,
framerate: framesPerSecond,
onProgress: onProgress,
//extension: ".mp4",
//codec: "libx264",
} );
capturer.start();
canvas = document.getElementById("testCanvas");
stage = new createjs.Stage(canvas);
var ball = new createjs.Shape();
ball.graphics.setStrokeStyle(5, 'round', 'round');
// eslint-disable-next-line quotes
ball.graphics.beginStroke('#000000');
ball.graphics.beginFill("#FF0000").drawCircle(0, 0, 50);
ball.graphics.setStrokeStyle(1, 'round', 'round');
ball.graphics.beginStroke('#000000');
ball.graphics.moveTo(0, 0);
ball.graphics.lineTo(0, 50);
ball.graphics.endStroke();
ball.x = 200;
ball.y = -50;
createjs.Tween.get(ball, {loop: -1})
.to({x: ball.x, y: canvas.height - 55, rotation: -360}, 1500, createjs.Ease.bounceOut)
.wait(1000)
.to({x: canvas.width - 55, rotation: 360}, 2500, createjs.Ease.bounceOut)
.wait(1000)
.to({scaleX: 2, scaleY: 2}, 2500, createjs.Ease.quadOut)
.wait(1000)
stage.addChild(ball);
createjs.Ticker.addEventListener("tick", stage);
function render() {
requestAnimationFrame(render);
capturer.capture( canvas );
++frameNum;
if (frameNum < numFrames) {
progressNode.nodeValue = "rendered frame# " + frameNum + " of " + numFrames;
} else if (frameNum === numFrames) {
capturer.stop();
capturer.save(showVideoLink);
}
}
render();
}
Everything works fine, you can test it yourself if you want by cloning the repo.
Right now animation rendering happens in client side, I would like this animation rendering to happen in the backend side
What do I need to change to make this animation rendering in backend server side using Nodejs? any help or suggestions will be appreciated.
Since you do all your animations in the canvas, you can use node-canvas to do the same in Node.js. (You have to double check that create.js also work in Node.js, though. If not, find another library or write those routines yourself).
Spawn ffmpeg into it's own process accepting input through a pipe (ffmpeg -i - -f rawvideo -pix_fmt rgba etc. The pipe will probably be different according to which server environment you use). After each frame is drawn, extract the image array using canvas.getContext('2d').getImageData(0, 0, width, height).data and pipe the result to to ffmpeg.
So first of all, I'm working with a JSON but I can't seem to put it here in my snippet so I'll just explain what I'm trying to do:
When you load the page it shows a collection of 5 phones and it has a validation form with a select and a submit. In the select there are options with the unique brands of the phones. If I select 'iPhone' for example i only want the phones with the brand 'iPhone' to show.
Everything works untill now but if i try to filter the list i get an error 'Cannot read property filter of undefined', i suppose because i return null but i can't seem to figure out the solution. I did some research and saw this question was already asked multiple times but i still can't find how to do it myself in this code of mine.
Any help would be useful thanks!
I am working with es6 btw:
{
let phones;
const initValidation = () => {
const $form = document.querySelector(`form`);
$form.noValidate = true;
$form.addEventListener(`submit`, handleSubmitForm);
}
const handleSubmitForm = e => {
const $form = e.target;
e.preventDefault();
if($form.checkValidity()){
const filteredPhones = getFilteredPhones();
createPhone(filteredPhones);
}
};
const getFilteredPhones = () => {
const brand = document.querySelector(`.brands`).value;
return phones.filter(phone => phone.brand == brand);
};
const setBrandOptions = brands => {
const $select = document.querySelector(`.brands`);
brands.sort().forEach(brand => {
const $option = document.createElement(`option`);
$option.value = brand;
$option.textContent = brand;
$select.appendChild($option);
});
};
const getUniqueBrands = phones => {
const uniqueBrands = [];
// for (let i = 0; i < phones.length; i++) {
// if (!uniqueBrands.includes(phones[i].brand)){
// uniqueBrands.push(phones[i].brand);
// console.log(phones[i].brand);
// }
// }
phones.forEach(phone => {
if(!uniqueBrands.includes(phone.brand)){
uniqueBrands.push(phone.brand);
console.log(phone.brand);
}
});
return uniqueBrands;
};
const createPhone = phones => {
const $div = document.createElement(`div`);
document.querySelector(`section`).appendChild($div);
const $img = document.createElement(`img`);
$img.setAttribute('src', phones.image);
$div.appendChild($img);
const $title = document.createElement(`h2`);
$title.textContent = phones.name;
$div.appendChild($title);
const $ul = document.createElement(`ul`);
$div.appendChild($ul);
$librand = document.createElement(`li`);
$librand.textContent = phones.brand;
$ul.appendChild($librand);
$liyear = document.createElement(`li`);
$liyear.textContent = phones.year;
$ul.appendChild($liyear);
};
const parseJSON = phones => {
console.log(phones);
phones.forEach(phone => createPhone(phone));
const brands = getUniqueBrands(phones);
setBrandOptions(brands);
};
const initJSON = () => {
const url = "assets/data/phones.json";
fetch(url)
.then(r => r.json())
.then(jsonObject => parseJSON(jsonObject));
};
const init = () => {
initJSON();
initValidation();
};
init();
}
body{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
section{
display: flex;
flex-direction: row;
justify-content: space-around;
align-items: flex-end;
}
div{
display: flex;
flex-direction: column;
padding-left: 3rem;
padding-right: 3rem;
}
h1{
border-bottom: .1rem solid black;
padding-right: 1rem;
padding-left: 1rem;
margin-bottom: 3rem;
}
img{
margin-bottom: 1rem;
height: 100%;
width: 100%;
}
h2{
font-family: sans-serif;
margin-left: 1rem;
font-size: 1.3rem;
}
ul{
margin-left: 1rem;
}
select{
margin-bottom: 2rem;
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title></title>
<link rel="stylesheet" href="css/reset.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<h1>My Phone Collection</h1>
<form action="">
<label for="brands">Brand:
<select id="brands" class="brands input">
<option value="All">All</option>
</select>
<span class="error"></span>
</label>
<button type="submit">Search</button>
</form>
<section></section>
<script type="text/javascript" src="js/script.js"></script>
</body>
</html>
There is some moment where phones is undefined so you have to set an empty array as its default value when you call array.prototype.filter.
So try to change this:
phones.filter(phone => phone.brand == brand);
To:
(phones || []).filter(phone => phone.brand == brand);
I looks like you are instantiating the phones variable on the fist line, but you are never assigning a value to it, so it will always be equal to undefined.
Check where you are getting the data for phones and make sure you are assigning it to the phones variable.