Vue - Convert html audio player into component - javascript

I'm converting a player in html into a Vue component.
Half of the component is already created, only the time control slider is missing.
Here is the html player code (Lines with multiple tabs are already implemented in the Vue component):
var audioPlayer = document.querySelector('.green-audio-player');
var playPause = audioPlayer.querySelector('#playPause');
var playpauseBtn = audioPlayer.querySelector('.play-pause-btn');
var loading = audioPlayer.querySelector('.loading');
var progress = audioPlayer.querySelector('.progress');
var sliders = audioPlayer.querySelectorAll('.slider');
var player = audioPlayer.querySelector('audio');
var currentTime = audioPlayer.querySelector('.current-time');
var totalTime = audioPlayer.querySelector('.total-time');
var speaker = audioPlayer.querySelector('#speaker');
var draggableClasses = ['pin'];
var currentlyDragged = null;
window.addEventListener('mousedown', function(event) {
if(!isDraggable(event.target)) return false;
currentlyDragged = event.target;
let handleMethod = currentlyDragged.dataset.method;
this.addEventListener('mousemove', window[handleMethod], false);
window.addEventListener('mouseup', () => {
currentlyDragged = false;
window.removeEventListener('mousemove', window[handleMethod], false);
}, false);
});
playpauseBtn.addEventListener('click', togglePlay);
player.addEventListener('timeupdate', updateProgress);
player.addEventListener('loadedmetadata', () => {
totalTime.textContent = formatTime(player.duration);
});
player.addEventListener('canplay', makePlay);
player.addEventListener('ended', function(){
playPause.attributes.d.value = "M18 12L0 24V0";
player.currentTime = 0;
});
sliders.forEach(slider => {
let pin = slider.querySelector('.pin');
slider.addEventListener('click', window[pin.dataset.method]);
});
function isDraggable(el) {
let canDrag = false;
let classes = Array.from(el.classList);
draggableClasses.forEach(draggable => {
if(classes.indexOf(draggable) !== -1)
canDrag = true;
})
return canDrag;
}
function inRange(event) {
let rangeBox = getRangeBox(event);
let rect = rangeBox.getBoundingClientRect();
let direction = rangeBox.dataset.direction;
if(direction == 'horizontal') {
var min = rangeBox.offsetLeft;
var max = min + rangeBox.offsetWidth;
if(event.clientX < min || event.clientX > max) return false;
} else {
var min = rect.top;
var max = min + rangeBox.offsetHeight;
if(event.clientY < min || event.clientY > max) return false;
}
return true;
}
function updateProgress() {
var current = player.currentTime;
var percent = (current / player.duration) * 100;
progress.style.width = percent + '%';
currentTime.textContent = formatTime(current);
}
function getRangeBox(event) {
let rangeBox = event.target;
let el = currentlyDragged;
if(event.type == 'click' && isDraggable(event.target)) {
rangeBox = event.target.parentElement.parentElement;
}
if(event.type == 'mousemove') {
rangeBox = el.parentElement.parentElement;
}
return rangeBox;
}
function getCoefficient(event) {
let slider = getRangeBox(event);
let rect = slider.getBoundingClientRect();
let K = 0;
if(slider.dataset.direction == 'horizontal') {
let offsetX = event.clientX - slider.offsetLeft;
let width = slider.clientWidth;
K = offsetX / width;
} else if(slider.dataset.direction == 'vertical') {
let height = slider.clientHeight;
var offsetY = event.clientY - rect.top;
K = 1 - offsetY / height;
}
return K;
}
function rewind(event) {
if(inRange(event)) {
player.currentTime = player.duration * getCoefficient(event);
}
}
function formatTime(time) {
var min = Math.floor(time / 60);
var sec = Math.floor(time % 60);
return min + ':' + ((sec<10) ? ('0' + sec) : sec);
}
function togglePlay() {
if(player.paused) {
playPause.attributes.d.value = "M0 0h6v24H0zM12 0h6v24h-6z";
player.play();
} else {
playPause.attributes.d.value = "M18 12L0 24V0";
player.pause();
}
}
function makePlay() {
playpauseBtn.style.display = 'block';
loading.style.display = 'none';
}
.audio.green-audio-player {
width: 400px;
min-width: 300px;
height: 56px;
box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.07);
display: flex;
justify-content: space-between;
align-items: center;
padding-left: 24px;
padding-right: 24px;
border-radius: 4px;
user-select: none;
-webkit-user-select: none;
background-color: #fff;
}
.audio.green-audio-player .play-pause-btn {
display: none;
cursor: pointer;
}
.audio.green-audio-player .spinner {
width: 18px;
height: 18px;
background-image: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/355309/loading.png);
background-size: cover;
background-repeat: no-repeat;
animation: spin 0.4s linear infinite;
}
.audio.green-audio-player .slider {
flex-grow: 1;
background-color: #D8D8D8;
cursor: pointer;
position: relative;
}
.audio.green-audio-player .slider .progress {
background-color: #44BFA3;
border-radius: inherit;
position: absolute;
pointer-events: none;
}
.audio.green-audio-player .slider .progress .pin {
height: 16px;
width: 16px;
border-radius: 8px;
background-color: #44BFA3;
position: absolute;
pointer-events: all;
box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.32);
}
.audio.green-audio-player .controls {
font-family: 'Roboto', sans-serif;
font-size: 16px;
line-height: 18px;
color: #55606E;
display: flex;
flex-grow: 1;
justify-content: space-between;
align-items: center;
margin-left: 24px;
}
.audio.green-audio-player .controls .slider {
margin-left: 16px;
margin-right: 16px;
border-radius: 2px;
height: 4px;
}
.audio.green-audio-player .controls .slider .progress {
width: 0;
height: 100%;
}
.audio.green-audio-player .controls .slider .progress .pin {
right: -8px;
top: -6px;
}
.audio.green-audio-player .controls span {
cursor: default;
}
svg, img {
display: block;
}
#keyframes spin {
from {
transform: rotateZ(0);
}
to {
transform: rotateZ(1turn);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div class="audio green-audio-player">
<div class="loading">
<div class="spinner"></div>
</div>
<div class="play-pause-btn">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="24" viewBox="0 0 18 24">
<path fill="#566574" fill-rule="evenodd" d="M18 12L0 24V0" class="play-pause-icon" id="playPause"/>
</svg>
</div>
<div class="controls">
<span class="current-time">0:00</span>
<div class="slider" data-direction="horizontal">
<div class="progress">
<div class="pin" id="progress-pin" data-method="rewind"></div>
</div>
</div>
<span class="total-time">0:00</span>
</div>
<audio>
<source src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/355309/Swing_Jazz_Drum.mp3" type="audio/mpeg">
</audio>
</div>
Html Codepen: https://codepen.io/caiokawasaki/pen/JwVwry
Here is the Vue component:
Vue.component('audio-player', {
props: ['message'],
data: () => ({
audio: undefined,
loaded: false,
playing: false,
currentTime: '00:00',
totalTime: '00:00',
percent: '0%',
draggableClasses: ['pin'],
currentlyDragged: null
}),
computed: {},
methods: {
formatTime(time) {
var min = Math.floor(time / 60);
var sec = Math.floor(time % 60);
return min + ':' + ((sec < 10) ? ('0' + sec) : sec);
},
loadedMetaData() {
this.totalTime = this.formatTime(this.audio.duration)
},
canPlay() {
this.loaded = true
},
timeUpdate(){
var current = this.audio.currentTime;
var percent = (current / this.audio.duration) * 100;
this.percent = percent + '%';
this.currentTime = this.formatTime(current);
},
ended(){
this.playing = false
this.audio.currentTime = 0
},
isDraggable(el) {
let canDrag = false;
let classes = Array.from(el.classList);
this.draggableClasses.forEach(draggable => {
if (classes.indexOf(draggable) !== -1)
canDrag = true;
})
return canDrag;
},
inRange(event) {
let rangeBox = getRangeBox(event);
let rect = rangeBox.getBoundingClientRect();
let direction = rangeBox.dataset.direction;
if (direction == 'horizontal') {
var min = rangeBox.offsetLeft;
var max = min + rangeBox.offsetWidth;
if (event.clientX < min || event.clientX > max) return false;
} else {
var min = rect.top;
var max = min + rangeBox.offsetHeight;
if (event.clientY < min || event.clientY > max) return false;
}
return true;
},
togglePlay() {
if (this.audio.paused) {
this.audio.play();
this.playing = true;
} else {
this.audio.pause();
this.playing = false;
}
},
makePlay() {
playpauseBtn.style.display = 'block';
loading.style.display = 'none';
},
getRangeBox(event) {
let rangeBox = event.target;
let el = currentlyDragged;
if (event.type == 'click' && isDraggable(event.target)) {
rangeBox = event.target.parentElement.parentElement;
}
if (event.type == 'mousemove') {
rangeBox = el.parentElement.parentElement;
}
return rangeBox;
},
getCoefficient(event) {
let slider = getRangeBox(event);
let rect = slider.getBoundingClientRect();
let K = 0;
if (slider.dataset.direction == 'horizontal') {
let offsetX = event.clientX - slider.offsetLeft;
let width = slider.clientWidth;
K = offsetX / width;
} else if (slider.dataset.direction == 'vertical') {
let height = slider.clientHeight;
var offsetY = event.clientY - rect.top;
K = 1 - offsetY / height;
}
return K;
},
rewind(event) {
if (this.inRange(event)) {
this.audio.currentTime = this.audio.duration * getCoefficient(event);
}
}
},
mounted() {
this.audio = this.$refs.audio
},
template: `<div class="audio-message-content">
<a v-if="loaded" class="play-pause-btn" href="#" :title="playing ? 'Clique aqui para pausar o audio' : 'Clique aqui ouvir o audio'" #click.prevent="togglePlay">
<svg key="pause" v-if="playing" x="0px" y="0px" viewBox="0 0 18 20" style="width: 18px; height: 20px; margin-top: -10px">
<path d="M17.1,20c0.49,0,0.9-0.43,0.9-0.96V0.96C18,0.43,17.6,0,17.1,0h-5.39c-0.49,0-0.9,0.43-0.9,0.96v18.07c0,0.53,0.4,0.96,0.9,0.96H17.1z M17.1,20"/>
<path d="M6.29,20c0.49,0,0.9-0.43,0.9-0.96V0.96C7.19,0.43,6.78,0,6.29,0H0.9C0.4,0,0,0.43,0,0.96v18.07C0,19.57,0.4,20,0.9,20H6.29z M6.29,20"/>
</svg>
<svg key="play" v-else x="0px" y="0px" viewBox="0 0 18 22" style="width: 18px; height: 22px; margin-top: -11px">
<path d="M17.45,10.01L1.61,0.14c-0.65-0.4-1.46,0.11-1.46,0.91V20.8c0,0.81,0.81,1.32,1.46,0.91l15.84-9.87C18.1,11.43,18.1,10.41,17.45,10.01L17.45,10.01z M17.45,10.01"/>
</svg>
</a>
<div v-else class="loading">
<div class="spinner"></div>
</div>
<div class="controls">
<span class="current-time">{{ currentTime }}</span>
<div class="slider" data-direction="horizontal" #click="">
<div class="progress" :style="{width: percent}">
<div class="pin" id="progress-pin" data-method="rewind"></div>
</div>
</div>
<span class="total-time">{{ totalTime }}</span>
</div>
<audio ref="audio" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/355309/Swing_Jazz_Drum.mp3" #loadedmetadata="loadedMetaData" #canplay="canPlay" #timeupdate="timeUpdate" #ended="ended"></audio>
</div>`
})
var app = new Vue({
el: '#app'
})
.audio-message-content {
width: 400px;
min-width: 300px;
height: 56px;
box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.07);
display: flex;
justify-content: space-between;
align-items: center;
padding-left: 24px;
padding-right: 24px;
border-radius: 4px;
user-select: none;
-webkit-user-select: none;
background-color: #fff;
}
.audio-message-content .play-pause-btn {
position: relative;
width: 18px;
height: 22px;
cursor: pointer;
}
.audio-message-content .play-pause-btn svg {
display: block;
position: absolute;
top: 50%;
left: 50%;
margin-left: -9px;
}
.audio-message-content .spinner {
width: 18px;
height: 18px;
background-image: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/355309/loading.png);
background-size: cover;
background-repeat: no-repeat;
animation: spin 0.4s linear infinite;
}
.audio-message-content .slider {
flex-grow: 1;
background-color: #D8D8D8;
cursor: pointer;
position: relative;
}
.audio-message-content .slider .progress {
background-color: #44BFA3;
border-radius: inherit;
position: absolute;
pointer-events: none;
}
.audio-message-content .slider .progress .pin {
height: 16px;
width: 16px;
border-radius: 8px;
background-color: #44BFA3;
position: absolute;
pointer-events: all;
box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.32);
}
.audio-message-content .controls {
font-family: 'Roboto', sans-serif;
font-size: 16px;
line-height: 18px;
color: #55606E;
display: flex;
flex-grow: 1;
justify-content: space-between;
align-items: center;
margin-left: 24px;
}
.audio-message-content .controls .slider {
margin-left: 16px;
margin-right: 16px;
border-radius: 2px;
height: 4px;
}
.audio-message-content .controls .slider .progress {
width: 0;
height: 100%;
}
.audio-message-content .controls .slider .progress .pin {
right: -8px;
top: -6px;
}
.audio-message-content .controls span {
cursor: default;
}
svg, img {
display: block;
}
#keyframes spin {
from {
transform: rotateZ(0);
}
to {
transform: rotateZ(1turn);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<audio-player></audio-player>
</div>
Vue Component Codepen: https://codepen.io/caiokawasaki/pen/QzRMwz
Functions like the following I could not understand nor find anything on the internet:
window[handleMethod]
window[pin.dataset.method]
Can anyone help me finalize this component?
Edit
I've converted all of the html and javascript into a Vue component but anyway it still is not working properly.
The only thing that is not working properly is the progress bar. It needs to perform two functions:
Clicking it should go to the desired time.
When clicking on the pin and drag it should go to the desired time.
I use Vue Cli, neither of the above two work in the form of .vue files, but in Codepen normally written only function 2 works.
Codepen: https://codepen.io/caiokawasaki/pen/VqOqBQ

The function: window[handleMethod] is executed by deriving the name of the method off of the data- property from the pin element:
<div class="pin" id="progress-pin" data-method="rewind"></div>
So window[handleMethod] is equivalent to window.rewind()
The same is true for window[pin.dataset.method].
So in your case:
this[handleMethod](event)
and:
this[pin.dataset.method](event)
Should be suitable replacements.

Related

HTML5 Canvas rectangles click coordinates is inconsistent

I made a canvas size as A4, i draw a rectangles inside and when i click the light blue rectangle it will call a function but the coordinates of the click on the rectangle is inconsistent and every row the y level is needed to click more lower then the light blue rectangle.
How i make the coordinates more accurate?
(Code need full screen)
'use strict';
function mmTopx(mm) {
//return mm * 3.7795275591;
//return mm * 3.7795275590551;
return (mm * 96) / 25.4;
}
function cmTopx(cm) {
return cm * 1; /* NEED TO FIX */
}
// Get mouse position
function getMousePos(c, evt) {
var rect = c.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top,
};
}
class sticker {
#width;
#height;
#fullheight;
constructor(width = 1, height = 1, fullheight = 1) {
if (!sticker.isNumber(width) || !sticker.isNumber(height) || !sticker.isNumber(fullheight)) throw 'Only accept number';
this.#width = width;
this.#height = height;
this.#fullheight = fullheight;
}
static isNumber(n) {
return !isNaN(parseFloat(n)) && !isNaN(n - 0) && typeof n != 'string';
}
get size() {
return { width: this.#width, height: this.#height, fullheight: this.#fullheight };
}
get width() {
return this.#width;
}
get height() {
return this.#height;
}
get fullheight() {
return this.#fullheight;
}
set width(n) {
if (!sticker.isNumber(n)) throw 'Only accept number';
this.#width = n;
}
set height(n) {
if (!sticker.isNumber(n)) throw 'Only accept number';
this.#height = n;
}
set fullheight(n) {
if (!sticker.isNumber(n)) throw 'Only accept number';
this.#fullheight = n;
}
}
window.onload = () => {
const controls = document.querySelectorAll('.control');
const canvas = document.querySelector('.A4');
const canvasPadding = {
left:
window
.getComputedStyle(canvas, null)
.getPropertyValue('padding-left')
.match(/\d+.\d+|\d+/)[0] - 0,
top:
window
.getComputedStyle(canvas, null)
.getPropertyValue('padding-top')
.match(/\d+.\d+|\d+/)[0] - 0,
};
/* ///////////////////////////////////////////////////// */
/* ///////////////////////////////////////////////////// */
/* ///// CANVAS ///// */
/* ///////////////////////////////////////////////////// */
/* canvas */
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
const ctx = canvas.getContext('2d');
const _sticker = new sticker(mmTopx(25), mmTopx(12), mmTopx(37));
let Stickers = [];
const drawSticker = (x, y, width, height, fullheight) => {
Stickers.push({
color: '#d8d8d8',
width: width,
height: height,
x: x,
y: y,
clicked: function () {
console.log(`you clicked me, ${this.x} ${this.y}`);
},
});
/* full area */
ctx.fillStyle = '#e8f2f8';
ctx.fillRect(x, y, width, fullheight); // x y width height
/* print area */
ctx.fillStyle = '#d8d8d8';
ctx.fillRect(x, y, width, height, fullheight); // x y width height
};
const render = () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
Stickers = [];
const size = _sticker.size;
for (let y = 0; y < canvas.height - size.fullheight; y += size.fullheight + 10) {
for (let x = 10; x < canvas.width - size.width; x += size.width + 1) {
drawSticker(x, y, size.width, size.height, size.fullheight);
}
}
};
/* ///////////////////////////////////////////////////// */
/* ///////////////////////////////////////////////////// */
/* ///// Event Listeners ///// */
/* ///////////////////////////////////////////////////// */
canvas.addEventListener('updateRender', (event) => {
const lengthType = event.detail.dimensionValue.match(/mm|cm/)[0];
let value = event.detail.dimensionValue.match(/\d+/)[0] - 0;
switch (lengthType) {
case 'cm':
//value = cmTopx(value);
break;
case 'mm':
default:
value = mmTopx(value);
break;
}
/* Set the new sticker size */
switch (event.detail.dimension) {
case 'width':
_sticker.width = value;
break;
case 'height':
_sticker.height = value;
break;
case 'fullheight':
_sticker.fullheight = value;
break;
}
render();
});
const event = new Event('change');
controls.forEach((_control) => {
_control.addEventListener(
'change',
(event) => {
const value = event.target.value;
const name = event.target.name;
const dimension = event.target.getAttribute('data-sticker-dim');
const detail = {};
detail['dimension'] = dimension;
detail['dimensionValue'] = value;
detail['name'] = name;
const updateSticker = new CustomEvent('updateRender', { detail: detail });
canvas.dispatchEvent(updateSticker);
},
true
);
const input = _control.querySelector('input');
input.dispatchEvent(event);
});
/* click event for text input */
canvas.addEventListener('click', function (e) {
e.preventDefault();
let x = parseInt(e.clientX - canvas.offsetLeft - canvasPadding.left);
let y = parseInt(e.clientY - canvas.offsetTop - canvasPadding.top);
if (x >= 0 && y >= 0) {
for (let index = 0; index < Stickers.length; index++) {
const _sticker = Stickers[index];
if (
x >= _sticker.x &&
x <= Math.floor(_sticker.x + _sticker.width) &&
y >= _sticker.y &&
y <= Math.floor(_sticker.y + _sticker.height)
) {
_sticker.clicked();
break;
}
}
}
});
/* ///////////////////////////////////////////////////// */
};
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
width: 100%;
height: 100%;
background-color: #fafafa;
}
/* //////////////////////////////////////////////////////////// */
.container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-self: flex-start;
overflow: auto;
}
/* //////////////////////////////////////////////////////////// */
.container .controllers {
position: sticky;
top: 50%;
transform: translateY(-50%);
width: 250px;
height: 500px;
flex: 0 0 100px;
border-radius: 20px;
box-sizing: border-box;
padding: 20px;
margin-left: 5px;
border: 1px solid #9e9e9e;
}
.container .controllers .control {
position: relative;
flex: 0 0 100%;
height: 50px;
padding: 5px;
}
.container .controllers .control:first-child {
margin-top: 5px;
}
.container .controllers .control:not(:first-child) {
margin-top: 20px;
}
.container .controllers .control label::before {
content: attr(data-placeholder);
position: absolute;
left: 20px;
top: 20px;
color: #65657b;
font-family: sans-serif;
line-height: 14px;
pointer-events: none;
transform-origin: 0 50%;
transition: transform 200ms, color 200ms;
}
.container .controllers .control .cut {
position: absolute;
border-radius: 10px;
height: 20px;
width: fit-content;
left: 20px;
top: -20px;
transform: translateY(0);
transition: transform 200ms;
}
.container .controllers .control input {
height: 100%;
padding: 4px 20px 0;
width: 100%;
background-color: #eeeeee;
border-radius: 12px;
border: 0;
outline: 0;
box-sizing: border-box;
color: #eee;
font-size: 18px;
color: black;
}
.container .controllers .control input:focus ~ .cut,
.container .controllers .control input:not(:placeholder-shown) ~ .cut {
transform: translateY(8px);
}
.container .controllers .control input:focus ~ label::before,
.container .controllers .control input:not(:placeholder-shown) ~ label::before {
content: attr(data-focus-placeholder);
transform: translateY(-30px) translateX(10px) scale(0.75);
}
.container .controllers .control input:not(:placeholder-shown) ~ label::before {
content: attr(data-focus-placeholder);
color: #808097;
}
.container .controllers .control input:focus ~ label::before {
color: #dc2f55;
}
/* //////////////////////////////////////////////////////////// */
.container textarea {
background: none;
outline: none;
}
.container .A4 {
align-self: center;
width: 21cm;
flex: 0 0 29.7cm;
padding: 1cm;
border: 1px #d3d3d3 solid;
border-radius: 5px;
background: #f5f5f5;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
}
/* //////////////////////////////////////////////////////////// */
#page {
size: A4;
margin: 0;
}
#media print {
html,
body {
height: 99%;
}
.page {
margin: 0;
border: initial;
border-radius: initial;
width: initial;
min-height: initial;
box-shadow: initial;
background: initial;
page-break-after: always;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<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>A4 Render Stickers</title>
</head>
<body>
<div class="container">
<div class="controllers">
<button>print</button>
<div class="control">
<input type="text" value="25mm" data-sticker-dim="width" name="printWidth" placeholder=" " />
<div class="cut"></div>
<label for="printWidth" data-focus-placeholder="Width print" data-placeholder="Width size of print area"></label>
</div>
<div class="control">
<input type="text" value="12mm" data-sticker-dim="height" name="printHeight" placeholder=" " />
<div class="cut"></div>
<label for="printHeight" data-focus-placeholder="Height print" data-placeholder="Height size of print area"></label>
</div>
<div class="control">
<input type="text" value="37mm" data-sticker-dim="fullheight" name="stikcerHeight" placeholder=" " />
<div class="cut"></div>
<label for="stikcerHeight" data-focus-placeholder="Full height sticker" data-placeholder="Height size of full sticker"></label>
</div>
</div>
<canvas width="800" height="800" class="A4"></canvas>
</div>
</body>
</html>

Double sided input slider in React, after reach initial range 0 also it move towards, left direction and increase the value, why?

I'm trying to know and fix the bug of the Double-sided input slider
the above slider start position is 0 but I'm getting a value of 52 due to incorrect cursor movement ex. after reach 0 the value I can able to move left direction
SCSS:
$border-radius: 20px;
$primary: #709fdc;
$base: #071739;
$shadow-color: #274684;
$lighter-shadow: rgba($shadow-color, .2);
$white: #fff;
$gray: #8c8c8c;
$lighter-gray: rgba($gray, .1);
$time-line-width: 240px;
$transition: .3s all ease;
#mixin dragIndicator($property, $background, $z-index) {
#{$property}{
position: absolute;
top: 0;
z-index: $z-index;
width: 0;
height: 5px;
border-radius: 5px;
background: $background;
&:hover{
&::before{
opacity: 1;
}
&::after{
opacity: 1;
}
}
&::before{
opacity: 0;
content: attr(data-content);
display: block;
position: absolute;
top: -40px;
right: -23px;
width: 40px;
padding: 3px;
text-align: center;
color: white;
background: $shadow-color;
border-radius: $border-radius;
}
&::after{
opacity: 0;
content:'';
display: block;
position: absolute;
top: -18px;
right: -8px;
border-top: 8px solid $shadow-color;
border-left:8px solid transparent;
border-right:8px solid transparent;
}
#{$property}-drag{
position: absolute;
right: -7.5px;
top: -5px;
width: 15px;
height: 15px;
border-radius: 50%;
background: $base;
transition: all .3s;
&:hover{
box-shadow: 0 0 0 6px $lighter-shadow;
}
}
}
}
body{
font-family: 'Rubik', sans-serif;
color: $base;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
background: $lighter-gray;
.card{
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 50px;
padding-top: 25px;
margin-top: 40px;
border-radius: $border-radius;
box-shadow: 0px 0px 20px 0px $lighter-shadow;
background: $white;
overflow: hidden;
h2{
margin-bottom: 40px;
}
.current-value{
width: 100%;
label{
display: inline-flex;
width: 50px;
font-size: 20px;
}
input{
margin: 0;
max-width: 40px;
margin-bottom: 5px;
font-size: 16px;
color: white;
padding: 5px;
padding-left: 15px;
border: none;
border-radius: $border-radius;
background: $shadow-color;
}
}
.values{
display: flex;
justify-content: space-between;
font-weight: 600;
margin-top: 30px;
margin-bottom: 10px;
width: $time-line-width;
}
#slider{
position: relative;
margin: 0 auto;
width: $time-line-width;
height: 5px;
background: $primary;
border-radius: 5px;
cursor: pointer;
#include dragIndicator("#min", $primary, 2);
#include dragIndicator("#max", $shadow-color, 1);
}
}
}
.fa-instagram{
position: absolute;
color: $base;
top: 3%;
right: 2%;
font-size: 38px;
}
.fa-instagram:hover{
font-size: 42px;
color: $shadow-color;
transition: all .1s linear;
cursor: pointer;
}
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
input[type="number"] {
-moz-appearance: textfield;
}
*:focus{
outline: none;
box-shadow: 0 0 0 2px $primary;
}
React Code:
class DoubleRangeSlider extends React.Component {
state = {
sliderWidth: 0,
offsetSliderWidht: 0,
min: 0,
max: 200,
minValueBetween: 10,
currentMin: 55,
inputMin: 55,
currentMax: 100,
inputMax: 100
};
componentDidMount() {
const { currentMin, currentMax, max } = this.state;
this.minValue.style.width = (currentMin*100)/max + "%";
this.maxValue.style.width = (currentMax*100)/max + "%";
this.setState({
sliderWidth: this.slider.offsetWidth,
offsetSliderWidht: this.slider.offsetLeft,
})
}
setMin = (e) => {
const { min, max, currentMax, minValueBetween } = this.state;
const inputMin = e.target.value;
this.setState({
inputMin
});
if((inputMin >= min) && (inputMin <= (currentMax-minValueBetween))){
this.setState({
currentMin: parseInt(inputMin)
});
this.minValue.style.width = (inputMin*100)/max + "%";
}
}
changeMinValue = (e) => {
e.preventDefault();
document.addEventListener('mousemove', this.onMouseMoveMin);
document.addEventListener('mouseup', this.onMouseUpMin);
document.addEventListener('touchmove', this.onMouseMoveMin);
document.addEventListener('touchend', this.onMouseUpMin);
}
onMouseMoveMin = (e) => {
const { min, max, currentMax, minValueBetween, sliderWidth, offsetSliderWidht } = this.state;
const dragedWidht = e.clientX - offsetSliderWidht;
const dragedWidhtInPercent = (dragedWidht*100)/sliderWidth;
const currentMin = Math.abs(parseInt((max * dragedWidhtInPercent)/100));
console.log(e.pageX, e.clientX, offsetSliderWidht);
console.log(currentMin , (currentMax-minValueBetween));
console.log((max * dragedWidhtInPercent)/100);
if( (currentMin >= min) && (currentMin <= (currentMax-minValueBetween))){
this.minValue.style.width = dragedWidhtInPercent + "%";
this.minValue.dataset.content = currentMin;
this.setState({
currentMin,
inputMin: currentMin
})
}
}
onMouseUpMin = () => {
document.removeEventListener('mouseup', this.onMouseUpMin);
document.removeEventListener('mousemove', this.onMouseMoveMin);
document.removeEventListener('touchend', this.onMouseMoveMin);
document.removeEventListener('touchmove', this.onMouseUpMin);
}
setMax = (e) => {
const { min, max, currentMin, currentMax, minValueBetween } = this.state;
const inputMax = e.target.value;
this.setState({
inputMax
});
if((inputMax >= currentMin + minValueBetween) && (inputMax <= max)){
this.setState({
currentMax: parseInt(inputMax)
});
this.maxValue.style.width = (inputMax*100)/max + "%";
}
}
changeMaxValue = (e) => {
e.preventDefault();
document.addEventListener('mousemove', this.onMouseMoveMax);
document.addEventListener('mouseup', this.onMouseUpMax);
document.addEventListener('touchmove', this.onMouseMoveMax);
document.addEventListener('touchend', this.onMouseUpMax);
}
onMouseMoveMax = (e) => {
const { max, currentMin, minValueBetween, sliderWidth, offsetSliderWidht} = this.state;
const maxWalueThumb = this.maxValue;
const dragedWidht = e.clientX - offsetSliderWidht;
const dragedWidhtInPercent = (dragedWidht*100)/sliderWidth;
const currentMax = Math.abs(parseInt((max * dragedWidhtInPercent)/100));
if( (currentMax >= (currentMin + minValueBetween)) && (currentMax <= max)){
maxWalueThumb.style.width = dragedWidhtInPercent + "%";
maxWalueThumb.dataset.content = currentMax;
this.setState({
currentMax,
inputMax: currentMax
})
}
}
onMouseUpMax = () => {
document.removeEventListener('mouseup', this.onMouseUp);
document.removeEventListener('mousemove', this.onMouseMoveMax);
document.removeEventListener('touchend', this.onMouseUp);
document.removeEventListener('touchmove', this.onMouseMoveMax);
}
maxForMin = () => {
const { currentMax, minValueBetween} = this.state;
return currentMax - minValueBetween;
}
minForMax = () => {
const { currentMin, minValueBetween} = this.state;
return currentMin + minValueBetween;
}
render() {
const { min, max, currentMin, inputMin, currentMax, inputMax, minValueBetween } = this.state;
return (
<div className="card">
<h2>Double range slider</h2>
<div className="current-value">
<label htmlFor="min-input">Min: </label>
<input
id="min-input"
type="number"
onChange={this.setMin}
value={inputMin}
min={min}
max={this.maxForMin}/>
<br/>
<label htmlFor="max-input">Max: </label>
<input
id="max-input"
type="number"
onChange={this.setMax}
value={inputMax}
min={this.minForMax}
max={max}/>
</div>
<div className="values">
<div>{ min }</div>
<div>{ max }</div>
</div>
<div ref={ref => this.slider = ref} id="slider">
<div ref={ref => this.minValue = ref} id="min" data-content={currentMin}>
<div ref={ref => this.minValueDrag = ref} id="min-drag" onMouseDown ={this.changeMinValue} onTouchStart={this.changeMinValue}></div>
</div>
<div ref={ref => this.maxValue = ref} id="max" data-content={currentMax}>
<div ref={ref => this.maxValueDrag = ref} id="max-drag" onMouseDown={this.changeMaxValue} onTouchStart={this.changeMaxValue}></div>
</div>
</div>
</div>
)
}
}
ReactDOM.render(
<DoubleRangeSlider/>,
document.getElementById('root')
)
source code: https://codepen.io/OlgaKoplik/pen/mdybLmE
Asked the same question in the Stackoverflow chat community, one of the members helped me to solve the above issue.
Issue:
const currentMin = Math.abs(parseInt((max * dragedWidhtInPercent)/100));
Solution: He Suggested removing the Math.abs() in currentMin const. After removal it's working fine, not moving after 0.
const currentMin = parseInt((max * dragedWidhtInPercent)/100);

Detect collision (video game js)

I am building a video game where fireballs drop from the top screen. The spaceship, moved by controllers, must avoid those fireballs in order win. My issue is that I do not know how to detect when the spaceship collides into fireballs. However, I found this link: Detect if animated object touched another object in DOM. I analysed this code and it seems it only works for his issue particularly. Do you guys know how to do this?
Code for image spaceship and fireball:
<img src="Photo/fireball.png" id="fireball">
<img src="Photo/Spaceship1.png" id="icon-p">
Code for spaceship:
let rect = icon
let pos = {top: 1000, left: 570}
const keys = {}
window.addEventListener("keydown", function(e) {keys[e.keyCode] = true})
window.addEventListener("keyup", function(e) {keys[e.keyCode] = false})
const loop = function() {
if (keys[37] || keys[81]) {pos.left -= 10}
if (keys[39] || keys[68]) {pos.left += 10}
if (keys[38] || keys[90]) {pos.top -= 10}
if (keys[40] || keys[83]) {pos.top += 10}
var owidth = display.offsetWidth
var oheight = display.offsetHeight
var iwidth = rect.offsetWidth
var iheight = rect.offsetHeight
if (pos.left < 0) pos.left = -10
if (pos.top < 0) pos.top = -10
if (pos.left + iwidth >= owidth) pos.left = owidth-iwidth
if (pos.top + iheight >= oheight) pos.top= oheight-iheight
rect.setAttribute("data", owidth + ":" + oheight)
rect.style.left = pos.left + "px"; rect.style.top = pos.top + "px"}
let sens = setInterval(loop, 1000 / 60)
Code for fireball:
function fFireball(offset) {
return Math.floor(Math.random() * (window.innerWidth - offset))}
let fireballElement = document.querySelector("#fireball");
let fireball = {x: fFireball(fireballElement.offsetWidth), y: 0}
const fireLoop = function() {
fireball.y += 2
fireballElement.style.top = fireball.y + 'px'
if (fireball.y > window.innerHeight) {
fireball.x = fFireball(fireballElement.offsetWidth)
fireballElement.style.left = fireball.x + 'px'; fireball.y = 0}}
fireballElement.style.left = fireball.x + 'px'
let fireInterval = setInterval(fireLoop, 1000 / 100)
Thanks!
here I've integrated collision detection for your game. The most notable thing is in this function:
function checkCollision() {
var elem = document.getElementById("icon");
var elem2 = document.getElementById("fireball");
if ( detectOverlap(elem, elem2) && elem2.getAttribute('hit')=='false' ){
hits++; // detect hit and increase
elem2.setAttribute('hit', true); // set attribute to not have flooding
console.log( hits ); // console it just to see it
}
setTimeout( checkCollision, 20);
}
In lower window you can test demo that I've built for you without images but some random boxes as images :)
Good luck with game man, cool
//////////
"use strict"
//Stay on focus
function stayOnFocus() {
setTimeout(function() {
alert("Do not exit window or game progression will be lost!")
}, 1000)
}
let hits = 0
//"A" keypress plays Music
document.addEventListener('keydown', function(e) {
if (e.keyCode !== 173) {
//document.getElementById('audio').play()
}
})
//Input Validation
let icon = document.getElementById("icon")
let fireballElement = document.querySelector("#fireball")
var input = document.getElementById("input")
input.addEventListener("keydown", function(event) {
if (event.keyCode === 13) {
event.preventDefault();
document.getElementById("begin-timer").click()
}
})
//CountDown (3...2...1)
var count = 3
function countDown() {
function preventCountFast() {
document.getElementById("count").innerHTML = count
if (count > 0) {
count--
} else {
clearInterval(ncount);
document.getElementById("count").style.display = "none"
}
}
var ncount = setInterval(preventCountFast, 1000)
}
//Name displayed + space(switch between images) + parameter icon displayed
function Username(field) {
field = input.value
if (field == "") {
alert("Complete blanks");
return false
}
document.getElementById("askName").style.display = "none"
setTimeout(function() {
document.getElementById("name").innerHTML = "Player: " + field
icon.style.display = 'block';
fireballElement.style.display = "block"
const images = ["https://placehold.it/30x30", "https://placehold.it/90x90",
"https://placehold.it/120x40", "https://placehold.it/100x100"
]
document.body.onkeyup = function(e) {
if (e.keyCode === 32) {
hits++;
icon.src = images[hits % 5]
}
}
checkCollision();
}, 4000)
}
//Spaceship moves into space + prevent going out borders
let display = document.getElementById("body");
let rect = icon
let pos = {
top: 1000,
left: 570
}
const keys = {}
window.addEventListener("keydown", function(e) {
keys[e.keyCode] = true
})
window.addEventListener("keyup", function(e) {
keys[e.keyCode] = false
})
const loop = function() {
if (keys[37] || keys[81]) {
pos.left -= 10
}
if (keys[39] || keys[68]) {
pos.left += 10
}
if (keys[38] || keys[90]) {
pos.top -= 10
}
if (keys[40] || keys[83]) {
pos.top += 10
}
var owidth = display.offsetWidth
var oheight = display.offsetHeight
var iwidth = rect.offsetWidth
var iheight = rect.offsetHeight
if (pos.left < 0) pos.left = -10
if (pos.top < 0) pos.top = -10
if (pos.left + iwidth >= owidth) pos.left = owidth - iwidth
if (pos.top + iheight >= oheight) pos.top = oheight - iheight
rect.setAttribute("data", owidth + ":" + oheight)
rect.style.left = pos.left + "px";
rect.style.top = pos.top + "px"
}
let sens = setInterval(loop, 1000 / 60)
//Parameter Sensibility
let param = document.getElementById("parameters")
let b2 = document.getElementById("body2")
document.getElementById("general").addEventListener("click", function() {
param.style.display = "block";
b2.style.display = "none"
})
function validateSens() {
b2.style.display = "block";
param.style.display = "none";
clearInterval(sens)
let sensibilty = parseFloat(document.getElementById("sensibilty").value)
switch (sensibilty) {
case 1:
sens = setInterval(loop, 1000 / 40);
break;
case 2:
sens = setInterval(loop, 1000 / 60);
break;
case 3:
sens = setInterval(loop, 1000 / 80);
break;
default:
alert("Sorry, a bug occured")
}
}
//Fireball script
function fFireball(offset) {
return Math.floor(Math.random() * (window.innerWidth - offset))
}
let fireball = {
x: fFireball(fireballElement.offsetWidth),
y: 0
}
const fireLoop = function() {
fireball.y += 2;
fireballElement.style.top = fireball.y + 'px'
if (fireball.y > window.innerHeight) {
fireball.x = fFireball(fireballElement.offsetWidth)
fireballElement.style.left = fireball.x + 'px';
fireball.y = 0;
fireballElement.setAttribute('hit', false );
}
}
fireballElement.style.left = fireball.x + 'px'
let fireInterval = setInterval(fireLoop, 1000 / 100)
function checkCollision() {
var elem = document.getElementById("icon");
var elem2 = document.getElementById("fireball");
if (detectOverlap(elem, elem2) && elem2.getAttribute('hit')=='false' ){
hits++; // detect hit
elem2.setAttribute('hit', true);
aler("hi")
}
setTimeout( checkCollision, 20);
}
// detect fn
var detectOverlap = (function() {
function getPositions(elem) {
var pos = elem.getBoundingClientRect();
return [
[pos.left, pos.right],
[pos.top, pos.bottom]
];
}
function comparePositions(p1, p2) {
var r1, r2;
r1 = p1[0] < p2[0] ? p1 : p2;
r2 = p1[0] < p2[0] ? p2 : p1;
return r1[1] > r2[0] || r1[0] === r2[0];
}
return function(a, b) {
var pos1 = getPositions(a),
pos2 = getPositions(b);
return comparePositions(pos1[0], pos2[0]) && comparePositions(pos1[1], pos2[1]);
};
})();
body {
user-select: none;
margin: 0px;
height: 100vh;
padding: 0;
width: 100%;
background-image: url(Photo/bg.jpg);
background-repeat: no-repeat;
background-attachment: fixed;
animation: intro-fade 3s;
background-size: cover;
overflow: hidden;
}
#askName {
display: block;
z-index: 1;
margin-left: auto;
margin-top: 12%;
margin-right: auto;
width: 400px;
text-align: center;
background-color: #737373;
opacity: 0.8;
border-radius: 15px;
padding: 40px 50px 40px 50px;
}
#askName:hover {
opacity: 0.9
}
#askName>label {
text-align: center;
font-size: 150%;
font-weight: lighter;
text-align: center;
}
#askName>input {
display: block;
font-size: 100%;
margin: 30px auto 20px auto;
border: none;
border-radius: 10px;
padding: 10px 20px 10px 20px;
}
#askName>button {
background-color: #e6e6e6;
cursor: pointer;
padding: 10px 20px 10px 20px;
border: none;
border-radius: 10px;
}
#count {
margin-top: 13%;
animation: count-down 16s;
font-weight: lighter;
font-family: cursive;
text-align: center;
color: black;
font-size: 200px;
}
h6 {
margin-right: 20px;
padding-top: 5px;
font-weight: normal;
font-family: sans-serif;
margin-top: 0px;
color: white;
text-align: center;
font-size: 190%;
cursor: default;
}
h6:hover {
font-size: 210%
}
#icon {
position: absolute;
top: 0;
left: 0;
cursor: none;
width: 9%;
}
#general {
position: absolute;
cursor: pointer;
min-width: 4%;
top: 10px;
width: 4%;
right: 10px;
}
#general:hover {
transform: rotate(-100deg)
}
#parameters {
text-align: center;
display: none;
animation: intro-fade 3s;
height: auto;
border: none;
background-color: #d9d9d9;
color: black;
position: absolute;
padding: 0px 60px 20px 60px;
left: 50%;
width: auto;
min-width: 200px;
top: 50%;
transform: translate(-50%, -50%);
border-radius: 13px;
}
h3 {
color: black;
font-weight: normal;
font-size: 150%;
}
#sensibilty {
display: block;
margin-right: auto;
margin-left: auto;
}
#validateSens {
margin-top: 20px;
border: none;
padding: 10px;
border-radius: 5px;
cursor: pointer;
}
#keyframes intro-fade {
from {
opacity: 0
}
to {
opacity: 1
}
}
#keyframes count-down {
from {
transform: scale(0)
}
to {
transform: scale(1)
}
}
<body id="body" onload="stayOnFocus()">
<img src="https://placehold.it/350x350" id="general">
<section id="parameters">
<h3> Choose your sensibility </h3>
<input type="range" id="sensibilty" min="1" max="3" value="2">
<button id="validateSens" onclick="validateSens()"> Submit </button>
</section>
<main id="body2">
<form id="askName" title="Write your name"> <label> Enter your username: </label>
<input id="input" type="text" maxlength="10" autofocus>
<button type="button" onclick="countDown(); return Username()" id="begin-timer"> Submit </button>
</form>
<h6 id="name"></h6>
<h2 id="count"></h2>
<img src="https://placehold.it/50x52" id="fireball" style="display:none; width:3%; position:absolute; cursor:none">
<img src="https://placehold.it/80x40" id="icon" style="display:none">
</main>

init function TypeError: Cannot read property 'style' of null

No matter how I wrote the code, I received the same message and I've been trying to fix this since last night, but I don't understand why this is bothering me so much.
I get the message that all these lines are wrong
I work according to my course and this code is from a course that works on video and it doesn't work for me, I've tried a lot of changes but it doesn't work.
document.getElementById('dice-1').style.display = 'block';
document.getElementById('dice-2').style.display = 'block';
var scores, roundScore, activePlayer, gamePlaying;
var lastDice;
function init() {
scores = [0, 0];
activePlayer = 0;
roundScore = 0;
gamePlaying = true;
document.getElementById('dice-1').style.display = 'none';
document.getElementById('dice-2').style.display = 'none';
document.getElementById('score-0').textContent = '0';
document.getElementById('score-1').textContent = '0';
document.getElementById('current-0').textContent = '0';
document.getElementById('current-1').textContent = '0';
document.getElementById('name-0').textContent = 'Player 1';
document.getElementById('name-1').textContent = 'Player 2';
document.querySelector('.player-0-panel').classList.remove('winner');
document.querySelector('.player-1-panel').classList.remove('winner');
document.querySelector('.player-0-panel').classList.remove('active');
document.querySelector('.player-1-panel').classList.remove('active');
document.querySelector('.player-0-panel').classList.add('active');
}
document.querySelector('.btn-roll').addEventListener('click', function() {
if(gamePlaying) {
var dice1 = Math.floor(Math.random() * 6) + 1;
var dice2 = Math.floor(Math.random() * 6) + 1;
document.getElementById('dice-1').style.display = 'block';
document.getElementById('dice-2').style.display = 'block';
document.getElementById('dice-1').src = 'dice-' + dice1 + '.png';
document.getElementById('dice-2').src = 'dice-' + dice2 + '.png';
if (dice1 !== 1 && dice2 !== 1) {
roundScore += dice1 + dice2;
document.querySelector('#current-' + activePlayer).textContent = roundScore;
} else {
nextPlayer();
}
}
});
document.querySelector('.btn-hold').addEventListener('click', function() {
if (gamePlaying) {
scores[activePlayer] += roundScore;
document.querySelector('#score-' + activePlayer).textContent = scores[activePlayer];
var input = document.querySelector('.final-score').value;
var winningScore;
if(input) {
winningScore = input;
} else {
winningScore = 100;
}
// Check if player won the game
if (scores[activePlayer] >= winningScore) {
document.querySelector('#name-' + activePlayer).textContent = 'Winner!';
document.getElementById('dice-1').style.display = 'none';
document.getElementById('dice-2').style.display = 'none';
document.querySelector('.player-' + activePlayer + '-panel').classList.add('winner');
document.querySelector('.player-' + activePlayer + '-panel').classList.remove('active');
gamePlaying = false;
} else {
nextPlayer();
}
}
});
function nextPlayer() {
activePlayer === 0 ? activePlayer = 1 : activePlayer = 0;
roundScore = 0;
document.getElementById('current-0').textContent = '0';
document.getElementById('current-1').textContent = '0';
document.querySelector('.player-0-panel').classList.toggle('active');
document.querySelector('.player-1-panel').classList.toggle('active');
document.getElementById('dice-1').style.display = 'none';
document.getElementById('dice-2').style.display = 'none';
}
document.querySelector('.btn-new').addEventListener('click', init);
init();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link href="https://fonts.googleapis.com/css?family=Lato:100,300,600" rel="stylesheet" type="text/css">
<link href="http://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css" rel="stylesheet" type="text/css">
<link type="text/css" rel="stylesheet" href="style.css">
<title>Pig Game</title>
</head>
<body>
<div class="wrapper clearfix">
<div class="player-0-panel active">
<div class="player-name" id="name-0">Player 1</div>
<div class="player-score" id="score-0">43</div>
<div class="player-current-box">
<div class="player-current-label">Current</div>
<div class="player-current-score" id="current-0">11</div>
</div>
</div>
<div class="player-1-panel">
<div class="player-name" id="name-1">Player 2</div>
<div class="player-score" id="score-1">72</div>
<div class="player-current-box">
<div class="player-current-label">Current</div>
<div class="player-current-score" id="current-1">0</div>
</div>
</div>
<button class="btn-new"><i class="ion-ios-plus-outline"></i>New game</button>
<button class="btn-roll"><i class="ion-ios-loop"></i>Roll dice</button>
<button class="btn-hold"><i class="ion-ios-download-outline"></i>Hold</button>
<input type="text" placeholder="Final Score" class="final-score">
<img src="dice-5.png" alt="Dice" class="dice">
</div>
<script type='text/javascript' src="challenges.js"></script>
</body>
</html>
/**********************************************
*** GENERAL
**********************************************/
.final-score {
position: absolute;
left: 50%;
transform: translateX(-50%);
top: 520px;
color: #555;
font-size: 18px;
font-family: 'Lato';
text-align: center;
padding: 10px;
width: 160px;
text-transform: uppercase;
}
.final-score:focus { outline: none; }
dice-1 { top: 120px; }
#dice-2 { top: 250px; }
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.clearfix::after {
content: "";
display: table;
clear: both;
}
body {
background-image: linear-gradient(rgba(62, 20, 20, 0.4), rgba(62, 20, 20, 0.4)), url(back.jpg);
background-size: cover;
background-position: center;
font-family: Lato;
font-weight: 300;
position: relative;
height: 100vh;
color: #555;
}
.wrapper {
width: 1000px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #fff;
box-shadow: 0px 10px 50px rgba(0, 0, 0, 0.3);
overflow: hidden;
}
.player-0-panel,
.player-1-panel {
width: 50%;
float: left;
height: 600px;
padding: 100px;
}
/**********************************************
*** PLAYERS
**********************************************/
.player-name {
font-size: 40px;
text-align: center;
text-transform: uppercase;
letter-spacing: 2px;
font-weight: 100;
margin-top: 20px;
margin-bottom: 10px;
position: relative;
}
.player-score {
text-align: center;
font-size: 80px;
font-weight: 100;
color: #EB4D4D;
margin-bottom: 130px;
}
.active { background-color: #f7f7f7; }
.active .player-name { font-weight: 300; }
.active .player-name::after {
content: "\2022";
font-size: 47px;
position: absolute;
color: #EB4D4D;
top: -7px;
right: 10px;
}
.player-current-box {
background-color: #EB4D4D;
color: #fff;
width: 40%;
margin: 0 auto;
padding: 12px;
text-align: center;
}
.player-current-label {
text-transform: uppercase;
margin-bottom: 10px;
font-size: 12px;
color: #222;
}
.player-current-score {
font-size: 30px;
}
button {
position: absolute;
width: 200px;
left: 50%;
transform: translateX(-50%);
color: #555;
background: none;
border: none;
font-family: Lato;
font-size: 20px;
text-transform: uppercase;
cursor: pointer;
font-weight: 300;
transition: background-color 0.3s, color 0.3s;
}
button:hover { font-weight: 600; }
button:hover i { margin-right: 20px; }
button:focus {
outline: none;
}
i {
color: #EB4D4D;
display: inline-block;
margin-right: 15px;
font-size: 32px;
line-height: 1;
vertical-align: text-top;
margin-top: -4px;
transition: margin 0.3s;
}
.btn-new { top: 45px;}
.btn-roll { top: 403px;}
.btn-hold { top: 467px;}
.dice {
position: absolute;
left: 50%;
top: 178px;
transform: translateX(-50%);
height: 100px;
box-shadow: 0px 10px 60px rgba(0, 0, 0, 0.10);
}
.winner { background-color: #f7f7f7; }
.winner .player-name { font-weight: 300; color: #EB4D4D; }
Please help me.
İn javascript , remove init(); or define init function.
try this:
function init() {
scores = [0, 0];
activePlayer = 0;
roundScore = 0;
gamePlaying = true;
document.getElementById('dice-1').style.display = 'none';
document.getElementById('dice-2').style.display = 'none';
document.getElementById('score-0').textContent = '0';
document.getElementById('score-1').textContent = '0';
document.getElementById('current-0').textContent = '0';
document.getElementById('current-1').textContent = '0';
document.getElementById('name-0').textContent = 'Player 1';
document.getElementById('name-1').textContent = 'Player 2';
document.querySelector('.player-0-panel').classList.remove('winner');
document.querySelector('.player-1-panel').classList.remove('winner');
document.querySelector('.player-0-panel').classList.remove('active');
document.querySelector('.player-1-panel').classList.remove('active');
document.querySelector('.player-0-panel').classList.add('active');
}
document.querySelector('.btn-roll').addEventListener('click', function() {
if(gamePlaying) {
var dice1 = Math.floor(Math.random() * 6) + 1;
var dice2 = Math.floor(Math.random() * 6) + 1;
document.getElementById('dice-1').style.display = 'block';
document.getElementById('dice-2').style.display = 'block';
document.getElementById('dice-1').src = 'dice-' + dice1 + '.png';
document.getElementById('dice-2').src = 'dice-' + dice2 + '.png';
if (dice1 !== 1 && dice2 !== 1) {
roundScore += dice1 + dice2;
document.querySelector('#current-' + activePlayer).textContent = roundScore;
} else {
nextPlayer();
}
}
});
document.querySelector('.btn-hold').addEventListener('click', function() {
if (gamePlaying) {
scores[activePlayer] += roundScore;
document.querySelector('#score-' + activePlayer).textContent = scores[activePlayer];
var input = document.querySelector('.final-score').value;
var winningScore;
if(input) {
winningScore = input;
} else {
winningScore = 100;
}
// Check if player won the game
if (scores[activePlayer] >= winningScore) {
document.querySelector('#name-' + activePlayer).textContent = 'Winner!';
document.getElementById('dice-1').style.display = 'none';
document.getElementById('dice-2').style.display = 'none';
document.querySelector('.player-' + activePlayer + '-panel').classList.add('winner');
document.querySelector('.player-' + activePlayer + '-panel').classList.remove('active');
gamePlaying = false;
} else {
nextPlayer();
}
}
});
function nextPlayer() {
activePlayer === 0 ? activePlayer = 1 : activePlayer = 0;
roundScore = 0;
document.getElementById('current-0').textContent = '0';
document.getElementById('current-1').textContent = '0';
document.querySelector('.player-0-panel').classList.toggle('active');
document.querySelector('.player-1-panel').classList.toggle('active');
document.getElementById('dice-1').style.display = 'none';
document.getElementById('dice-2').style.display = 'none';
}
document.querySelector('.btn-new').addEventListener('click', init);
function init(){
}
I don't see any HTML elements with id="dice-1" nor id="dice-2", which would explain the error you're receiving.
I don't see element with id="dice-1" or id="dice-2" in your template (HTML), so the error just means, that element with that id doesn't exist, so it's value is null.

Audio player not working for multiple audios

I have created an audio player using javascript,
with the below Javascript, html, css I am getting expected result for one audio file in the HTML, when i add another audio file in the html, its not working.
Can you please anyone suggest how this can be handled for multiple audio files in the HTML?
Javascript
function calculateTotalValue(length) {
var minutes = Math.floor(length / 60),
seconds_int = length - minutes * 60,
seconds_str = seconds_int.toString(),
seconds = seconds_str.substr(0, 2),
time = minutes + ':' + seconds
return time;
}
function calculateCurrentValue(currentTime) {
var current_hour = parseInt(currentTime / 3600) % 24,
current_minute = parseInt(currentTime / 60) % 60,
current_seconds_long = currentTime % 60,
current_seconds = current_seconds_long.toFixed(),
current_time = (current_minute < 10 ? "0" + current_minute : current_minute) + ":" + (current_seconds < 10 ? "0" + current_seconds : current_seconds);
return current_time;
}
function initProgressBar() {
var player = document.getElementById('player');
var length = player.duration
var current_time = player.currentTime;
// calculate total length of value
var totalLength = calculateTotalValue(length)
jQuery(".end-time").html(totalLength);
// calculate current value time
var currentTime = calculateCurrentValue(current_time);
jQuery(".start-time").html(currentTime);
var progressbar = document.getElementById('seekObj');
progressbar.value = (player.currentTime / player.duration);
progressbar.addEventListener("click", seek);
if (player.currentTime == player.duration) {
$('#play-btn').removeClass('pause');
}
function seek(evt) {
var percent = evt.offsetX / this.offsetWidth;
player.currentTime = percent * player.duration;
progressbar.value = percent / 100;
}
};
function initPlayers(num) {
for (var i = 0; i < num; i++) {
(function() {
var playerContainer = document.getElementById('player-container'),
player = document.getElementById('player'),
isPlaying = false,
playBtn = document.getElementById('play-btn');
if (playBtn != null) {
playBtn.addEventListener('click', function() {
togglePlay()
});
}
// Controls & Sounds Methods
// ----------------------------------------------------------
function togglePlay() {
if (player.paused === false) {
player.pause();
isPlaying = false;
$('#play-btn').removeClass('pause');
} else {
player.play();
$('#play-btn').addClass('pause');
isPlaying = true;
}
}
}());
}
}
function muteAud(){
if (player.muted === false) {
player.muted = true;
$('#btn_muteUnmute').addClass('mute');
}
else
{
player.muted = false;
$('#btn_muteUnmute').removeClass('mute');
}
}
initPlayers(jQuery('#player-container').length);
Here is the HTML:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops">
<head>
<meta charset="utf-8"/>
<link rel="stylesheet" href="css/style.css"/>
</head>
<body>
<div class="audio-player">
<div id="play-btn"></div>
<div class="audio-wrapper" id="player-container">
<audio id="player" ontimeupdate="initProgressBar()">
<source
src="mmc03-01-9780128023198.mp3" type="audio/mp3"/></audio>
</div>
<div class="player-controls scrubber">
<div id="seekObjContainer">
<progress id="seekObj" value="0" max="1"></progress>
</div>
<small style="float: left; position: relative; left: 15px;" class="start-time"></small>
<small style="float: right; position: relative; right: 20px;" class="end-time"></small>
<div id="btn_muteUnmute"></div>
</div>
</div>
<script src="js/jquery.min.js"></script>
<script src="js/index.js"></script>
</body>
</html>
CSS:
html {
height: 100%;
display: table;
margin: auto;
}
body {
height: 100%;
display: table-cell;
vertical-align: middle;
}
.start-time
{
margin: 0rem 0rem 0 0rem;
}
.end-time
{
margin: 0rem 15rem 0 0rem;
}
.audio-player {
background: white;
width: 50vw;
text-align: center;
display: flex;
flex-flow: row;
margin: 4rem 0 4rem 0;
}
.audio-player .player-controls {
align-items: center;
justify-content: center;
margin-top: 2.5rem;
flex: 3;
}
.audio-player .player-controls progress {
width: 70%;
margin-left: -15.5rem;
}
.audio-player .player-controls progress[value] {
-webkit-appearance: none;
appearance: none;
background-color: white;
color: grey;
height: 6px;
}
.audio-player .player-controls progress[value]::-webkit-progress-bar {
background-color: #d3d3d3;
border-radius: 2px;
border: 1px solid #dfdfdf;
color: grey;
}
.audio-player .player-controls progress::-webkit-progress-value {
background-color: grey;
}
.audio-player .player-controls p {
font-size: 1.6rem;
}
.audio-player #play-btn {
background-image: url("../img/play.png");
background-size: cover;
width: 25px;
height: 25px;
margin: 2.7rem 0 2rem 2rem;
}
.audio-player #play-btn.pause {
background-image: url("../img/pause.png");
}
.audio-player #btn_muteUnmute {
background-image: url("../img/unmute.png");
background-size: cover;
width: 25px;
height: 25px;
margin: -1.9rem 0 2rem 48rem;
}
.audio-player #btn_muteUnmute.mute {
background-image: url("../img/mute.png");
}
html{font-size:10px;)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}
Here you id instead of class:
Change some of your code like this:
var playerContainer = document.querySelectorAll('.player-container'),
player = document.querySelectorAll('.player'),
isPlaying = false,
playBtn = document.querySelectorAll('.play-btn');
Note: You should loop through the element playerContainer, player and playBtn variable because querySelectorAll returns a list of Node.
Advice: if you use jQuery, use it for the selector.

Categories

Resources