HTML5 Canvas rectangles click coordinates is inconsistent - javascript

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>

Related

Detecting the collision of 2 divs with JavaScript

I'm making a simple Space Invaders Clone in Web and ran into an issue. The code works well so far with the exception of the collision system. I need to destroy an enemy every time that the player's bullet hits it. In order to make it, I'm grabbing the x and y coordinates of both the enemies' div and the bullet's div. The issue appears on the values comparison: apparently getBoundingClientRect() grabs the x and y coordinates from within the element excluding its real size. Hence, according to my code, only when the bullet is perfectly inside the enemy that things would trigger. Is there a better way of doing it? How so?
Thanks in advance.
const shoot = (x) => {
//Creates bullet
const main = document.getElementById("main");
const div_bullet = document.createElement("div");
//Appends child
main.appendChild(div_bullet);
//Sets position
div_bullet.style.top = "340px";
div_bullet.style.left = x + "px";
//Gives it a class
div_bullet.classList.add("div_bullet");
div_bullet.setAttribute("id", "bullet");
//Deletes bullet
setTimeout(() => {
div_bullet.remove();
}, 1000);
};
const load_game = () => {
//Adding movement to the spaceship
const space_ship = document.getElementById("space_ship");
let x = 375;
window.addEventListener("keydown", (e) => {
switch (e.key) {
case "ArrowLeft":
if (x <= 15) break;
x = x - 10;
space_ship.style.left = x + "px";
break;
case "ArrowRight":
if (x >= 725) break;
x = x + 10;
space_ship.style.left = x + "px";
break;
case "ArrowUp":
if (document.getElementsByClassName("div_bullet").length === 0)
shoot(x + 20);
break;
default:
break;
}
});
};
const collision_system = () => {
setInterval(() => {
//Checks if any enemy was hit
const e1 = document.getElementById("e1");
const e2 = document.getElementById("e2");
const e3 = document.getElementById("e3");
const e4 = document.getElementById("e4");
const e5 = document.getElementById("e5");
const enemies_position = [{
x: e1.getBoundingClientRect().x,
y: e1.getBoundingClientRect().y
},
{
x: e2.getBoundingClientRect().x,
y: e2.getBoundingClientRect().y
},
{
x: e3.getBoundingClientRect().x,
y: e3.getBoundingClientRect().y
},
{
x: e4.getBoundingClientRect().x,
y: e4.getBoundingClientRect().y
},
{
x: e5.getBoundingClientRect().x,
y: e5.getBoundingClientRect().y
},
];
if (document.getElementById("bullet")) {
const x_bullet = document
.getElementById("bullet")
.getBoundingClientRect().x;
const y_bullet = document
.getElementById("bullet")
.getBoundingClientRect().y;
console.log(
"X: " + enemies_position[0].x + "Y: " + enemies_position[0].y
);
console.log("X bullet: " + x_bullet + "Y bullet : " + y_bullet);
for (let i = 0; i < 5; i++) {
if (
enemies_position[i].x === x_bullet &&
enemies_position[i].y === y_bullet
)
alert("Shoot!");
}
}
}, 10);
};
document.addEventListener("DOMContentLoaded", () => {
load_game();
collision_system();
});
* {
padding: 0px;
margin: 0px;
}
body {
background-color: black;
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.main {
width: 800px;
height: 500px;
border: 2px white solid;
border-radius: 10px;
}
#keyframes enemies_move {
from {
left: 80px;
}
to {
left: -80px;
}
}
.enemies {
margin-top: 20px;
position: fixed;
width: 800px;
height: 50px;
display: flex;
justify-content: space-evenly;
}
.enemies div {
position: relative;
width: 50px;
height: 50px;
background-color: orange;
animation: enemies_move 4s alternate infinite;
}
.barriers {
width: 800px;
height: 20px;
position: fixed;
top: 460px;
display: flex;
justify-content: space-evenly;
}
.barriers div {
width: 100px;
height: 20px;
background-color: white;
}
.space_ship {
width: 50px;
height: 50px;
border: 2px white solid;
position: relative;
top: 440px;
left: 375px;
}
#keyframes shoot_bullet {
from {
top: 340px;
}
to {
top: -50px;
}
}
.div_bullet {
left: 17px;
width: 15px;
height: 40px;
background-color: white;
position: relative;
animation: shoot_bullet 1s;
}
<div id="main" class="main">
<div class="enemies">
<div id="e1"></div>
<div id="e2"></div>
<div id="e3"></div>
<div id="e4"></div>
<div id="e5"></div>
</div>
<div class="barriers">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div id="space_ship" class="space_ship"></div>
</div>
The problem in your code is that you are using only the x and y of the bullet and enemy to check for collisions. You need to use the width and height of both items to check if they collide.
The checks needed to see if two rects collide is
function rectCollision(rectA, rectB) {
return (
rectA.x < rectB.x + rectB.width &&
rectA.x + rectA.width > rectB.x &&
rectA.y < rectB.y + rectB.height &&
rectA.height + rectA.y > rectB.y
);
}
And using this in your code makes it work
const shoot = (x) => {
//Creates bullet
const main = document.getElementById("main");
const div_bullet = document.createElement("div");
//Appends child
main.appendChild(div_bullet);
//Sets position
div_bullet.style.top = "340px";
div_bullet.style.left = x + "px";
//Gives it a class
div_bullet.classList.add("div_bullet");
div_bullet.setAttribute("id", "bullet");
//Deletes bullet
setTimeout(() => {
div_bullet.remove();
}, 1000);
};
const load_game = () => {
//Adding movement to the spaceship
const space_ship = document.getElementById("space_ship");
let x = 375;
window.addEventListener("keydown", (e) => {
switch (e.key) {
case "ArrowLeft":
if (x <= 15) break;
x = x - 10;
space_ship.style.left = x + "px";
break;
case "ArrowRight":
if (x >= 725) break;
x = x + 10;
space_ship.style.left = x + "px";
break;
case "ArrowUp":
if (document.getElementsByClassName("div_bullet").length === 0)
shoot(x + 20);
break;
default:
break;
}
});
};
const collision_system = () => {
setInterval(() => {
//Checks if any enemy was hit
const e1 = document.getElementById("e1");
const e2 = document.getElementById("e2");
const e3 = document.getElementById("e3");
const e4 = document.getElementById("e4");
const e5 = document.getElementById("e5");
const enemies_position = [
e1.getBoundingClientRect(),
e2.getBoundingClientRect(),
e3.getBoundingClientRect(),
e4.getBoundingClientRect(),
e5.getBoundingClientRect(),
];
if (document.getElementById("bullet")) {
const bullet = document
.getElementById("bullet")
.getBoundingClientRect();
console.log(
"X: " + enemies_position[0].x + "Y: " + enemies_position[0].y
);
console.log("X bullet: " + bullet.x + "Y bullet : " + bullet.y);
for (let i = 0; i < 5; i++) {
if (
rectCollision(enemies_position[i], bullet)
)
alert("Shoot!");
}
}
}, 10);
};
function rectCollision(rectA, rectB) {
return (rectA.x < rectB.x + rectB.width &&
rectA.x + rectA.width > rectB.x &&
rectA.y < rectB.y + rectB.height &&
rectA.height + rectA.y > rectB.y)
}
document.addEventListener("DOMContentLoaded", () => {
load_game();
collision_system();
});
* {
padding: 0px;
margin: 0px;
}
body {
background-color: black;
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.main {
width: 800px;
height: 500px;
border: 2px white solid;
border-radius: 10px;
}
#keyframes enemies_move {
from {
left: 80px;
}
to {
left: -80px;
}
}
.enemies {
margin-top: 20px;
position: fixed;
width: 800px;
height: 50px;
display: flex;
justify-content: space-evenly;
}
.enemies div {
position: relative;
width: 50px;
height: 50px;
background-color: orange;
animation: enemies_move 4s alternate infinite;
}
.barriers {
width: 800px;
height: 20px;
position: fixed;
top: 460px;
display: flex;
justify-content: space-evenly;
}
.barriers div {
width: 100px;
height: 20px;
background-color: white;
}
.space_ship {
width: 50px;
height: 50px;
border: 2px white solid;
position: relative;
top: 440px;
left: 375px;
}
#keyframes shoot_bullet {
from {
top: 340px;
}
to {
top: -50px;
}
}
.div_bullet {
left: 17px;
width: 15px;
height: 40px;
background-color: white;
position: relative;
animation: shoot_bullet 1s;
}
<div id="main" class="main">
<div class="enemies">
<div id="e1"></div>
<div id="e2"></div>
<div id="e3"></div>
<div id="e4"></div>
<div id="e5"></div>
</div>
<div class="barriers">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div id="space_ship" class="space_ship"></div>
</div>

Vue - Convert html audio player into component

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.

Why is there a random space when you click on this button?

I have been trying to replicate some material design buttons but have run into an issue with the div that is generated to create the "ripple" effect. If you go to my codepen at https://codepen.io/AlexStiles/pen/oPomzX you will see the issue.
This is caused by the div (I tried deleting it and it fixed the problem). I have tried adding a variety of properties such as font-size and line-height to no avail. Interestingly, depending on your browser the issue seems to have a different effect. On safari the width increases hugely then it decreases to the chrome width.
"use strict";
const buttons = document.getElementsByTagName("button");
const overlay = document.getElementsByClassName("overlay");
const animationTime = 600;
for (let i = 0; i < buttons.length; i++) {
buttons[i].addEventListener("click", createRipple);
};
let circle = document.createElement("div");
function createRipple(e) {
this.appendChild(circle);
var d = Math.max(this.scrollWidth, this.scrollHeight);
circle.style.width = circle.style.height = d + "px";
circle.style.left = e.clientX - this.offsetLeft - d / 2 + "px";
circle.style.top = e.clientY - this.offsetTop - d / 2 + "px";
circle.classList.add("ripple");
// setTimeout(function(){
// for (let i = 0; i < circle.length; i++)
// document.getElementsByClassName("ripple")[i].remove();
// }, animationTime);
}
button {
background-color: #4888f1;
border-radius: 24px;
display: flex;
align-items: center;
outline: 0;
border: 0;
padding: 10px 22px;
cursor: pointer;
overflow: hidden;
position: relative;
}
button .ripple {
position: absolute;
border-radius: 50%;
background-color: rgba(255, 255, 255, 0.5);
transform: scale(0);
animation: ripple 0.5s linear;
font-size: 0;
line-height: 0;
}
#keyframes ripple {
to {
transform: scale(2.5);
opacity: 0;
}
}
button img {
width: 20px;
height: 20px;
}
button *:not(:last-child) {
margin: 0 8px 0 0;
}
button span {
color: #fff;
font-family: Futura;
}
#media screen and (min-width: 1280px) {
button {
padding: 0.8vw 1.75vw;
border-radius: 1.9vw;
} button img {
width: 1.55vw;
height: auto;
} button span {
font-size: 0.8vw;
}
}
<html>
<head>
<title>Material Design Components</title>
<link rel="stylesheet" href="style.css">
</head>
<button>
<span>Add to Cart</span>
</button>
<script src="js.js"></script>
</html>
Change
button *:not(:last-child) {
margin: 0 8px 0 0;
}
To,
button *:not(:last-child) {
margin: 0 0 0 0;
}
Checked in firefox.
When you add the ripple element you make it the last-child thus the rule of margin button *:not(:last-child) will apply to span since this one is no more the last child.
To fix this remove margin from the span:
"use strict";
const buttons = document.getElementsByTagName("button");
const overlay = document.getElementsByClassName("overlay");
const animationTime = 600;
for (let i = 0; i < buttons.length; i++) {
buttons[i].addEventListener("click", createRipple);
};
let circle = document.createElement("div");
function createRipple(e) {
this.appendChild(circle);
var d = Math.max(this.scrollWidth, this.scrollHeight);
circle.style.width = circle.style.height = d + "px";
circle.style.left = e.clientX - this.offsetLeft - d / 2 + "px";
circle.style.top = e.clientY - this.offsetTop - d / 2 + "px";
circle.classList.add("ripple");
// setTimeout(function(){
// for (let i = 0; i < circle.length; i++)
// document.getElementsByClassName("ripple")[i].remove();
// }, animationTime);
}
button {
background-color: #4888f1;
border-radius: 24px;
display: flex;
align-items: center;
outline: 0;
border: 0;
padding: 10px 22px;
cursor: pointer;
overflow: hidden;
position: relative;
}
button .ripple {
position: absolute;
border-radius: 50%;
background-color: rgba(255, 255, 255, 0.5);
transform: scale(0);
animation: ripple 0.5s linear;
font-size: 0;
line-height: 0;
}
#keyframes ripple {
to {
transform: scale(2.5);
opacity: 0;
}
}
button img {
width: 20px;
height: 20px;
}
button *:not(:last-child) {
margin: 0 8px 0 0;
}
button span:first-child {
color: #fff;
font-family: Futura;
margin:0;
}
#media screen and (min-width: 1280px) {
button {
padding: 0.8vw 1.75vw;
border-radius: 1.9vw;
} button img {
width: 1.55vw;
height: auto;
} button span {
font-size: 0.8vw;
}
}
<html>
<head>
<title>Material Design Components</title>
<link rel="stylesheet" href="style.css">
</head>
<button>
<span>Add to Cart</span>
</button>
<script src="js.js"></script>
</html>

How to save innerHTML of div in a local storage?

I want to save and restore data from div - that is container of other divs,
In order to make it I use local storage and JSON like this:
window.onload = restoreJason;
function makeJson(){
var canvas = document.getElementById("canvas");
var shapes = canvas.querySelectorAll("div[class='drag']");
var divs = new Object();
for(var i=0; i<shapes.length; ++i){
divs[shapes[i].getAttribute('innerHTML')] = shapes[i].innerHTML;
}
localStorage.setItem("divs", JSON.stringify(divs));
}
function restoreJason(){
var divs = JSON.parse(localStorage.getItem("divs"));
var canvas = document.getElementById("canvas");
var shapes = canvas.querySelectorAll("div[class='drag']");
for(var i = 0; i<shapes.length; i++){
shapes[i].value = divs[shapes[i].getAttribute("innerHTML")];
}
console.log(divs);
}
However, I don't know how to access the innerHTML of the elements and save it or restore it.
What do you think I shall do?
(To be more detailed - I need to save the content of the div when user click on "save", and load it when the user click "load". This is a snippest of it...)
NOTICE: the "canvas" is just the id of the main div, and not a real "canvas".
function randomizeColor() {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * letters.length)];
}
return color;
}
function randomizeRectangle() {
var width = Math.random() * 700 + 50;
var height = Math.random() * 250 + 50;
if (height <= 20) {
height = 20;
}
var posX = Math.round(Math.random() * window.innerWidth);
var posY = Math.round(Math.random() * window.innerHeight);
var randomRecObj = {
"width": width + "px",
"height": height + "px",
"posX": posX,
"posY": posY
};
return randomRecObj;
}
function makeShape() {
var rect = randomizeRectangle();
var rectDOM = document.createElement("div");
rectDOM.className = "rectangle";
rectDOM.style.border = "1px solid black";
rectDOM.style.width = rect.width;
rectDOM.style.height = rect.height;
rectDOM.style.background = randomizeColor();
rectDOM.style.top = rect.posY + "px";
rectDOM.style.left = rect.posX + "px";
//rectDOM.addEventListener("click", selectShape);
// rectDOM.style.transform =rect.rotation;
return rectDOM;
}
function randRect() {
var rectDOM = makeShape();
var canvas = document.getElementById("canvas");
canvas.appendChild(rectDOM);
}
function randOval() {
var ovalDOM = makeShape();
ovalDOM.style.borderRadius = "50%";
var canvas = document.getElementById("canvas");
canvas.appendChild(ovalDOM);
}
function changeColor(){
}
function cancelSelection() {
var selected = document.getElementsByClassName("selected");
while (selected) {
selected[0].classList.remove(selected[0]);
}
}
function removeShape(event) {
var selectedShapes = document.getElementsByClassName("selected");
var len = selectedShapes.length;
while (len > 0) {
selectedShapes[0].parentNode.removeChild(selectedShapes[0]);
--len;
}
}
function removeCorners(rectDom) {
var corners = document.getElementsByClassName("corners");
var len = corners.length;
while (len > 0) {
corners[0].classList.remove("corners");
--len;
}
}
.header{
background: #4ABDAC;
color: #fff;
margin: 1px;
}
hr{
border-top: 3px double #2a3132;
}
ul{
list-style: none;
margin: 0;
padding: 0;
overflow: hidden;
background-color: #90afc5;
}
li{
float: left;
border: 2px solid #336b87;
padding: 3px;
margin: 3px;
}
li>a{
display: block;
color: #2a3132;
text-decoration: none;
padding: 10px 14px;
}
#color{
margin-left: 150px;
}
#rect{
margin-left: 100px;
}
li>a:hover{
color: #763626;
cursor: pointer;
}
#canvas{
background: #66a5ad;
position: relative;
height: 1200px;
width: 100%;
}
.corners{
position: absolute;
height: 10px;
width: 10px;
background:#fff;
border: 1px solid black;
display: none;
}
.selected .corners{
display: inline-block;
}
.cornerUpLeft{
top: -5px;
left: -5px;
}
.cornerUpRight{
top: -5px;
right: -5px;
}
.cornerBtmLeft{
bottom: -5px;
left: -5px;
}
.cornerBtmRight{
bottom: -5px;
right: -5px;
}
.rectangle{
position: absolute;
}
.colorBox{
border: 1px solid black;
height: 20px;
width: 20px;
list-style: none;
}
<!DOCTYPE html>
<html lang="en">
<head>
<title>Sketch Board - Eyal Segal Project</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="css/style.css" rel="stylesheet">
<script src="js/sketch.js"></script>
</head>
<body>
<h1 class="header">Sketch Board</h1>
<div>
<ul class="toolbar">
<li><a>Load</a></li>
<li id="Save"><a>Save</a></li>
<li id="rect"><a onclick="randRect()">Rectangle</a></li>
<li><a onclick="randOval()">Oval</a></li>
</ul>
<hr>
</div>
<div class="canvas" id="canvas">
</div>
</body>
</html>
All you need to do is set the .innerHTML of the div id="canvas" into localStorage. There's no need for JSON or loops at all.
Also, don't use inline HTML event attributes (onclick). Instead, do all your JavaScript separately using modern, standards based event handling.
Lastly, there is no need for <a> elements to be able to respond to a click event. Actually, your a elements are invalid as they don't have a name or href attribute anyway. The li elements can simply be set up for click events.
This is the code to do it but it won't execute here in the Stack Overflow snippet environment, but you can see it working here.
// Get reference to the "canvas"
var can = document.getElementById("canvas");
// Save the content of the canvas to localStorage
function saveData(){
localStorage.setItem("canvas", can.innerHTML);
}
// Get localStorage data
function restoreData(){
can.innerHTML = localStorage.getItem("canvas");
}
// get load and save references
var load = document.getElementById("load");
var save = document.getElementById("save");
// Set up event handlers
load.addEventListener("click", restoreData);
save.addEventListener("click", saveData);
// Get references to the rect and oval "buttons" and set their event handlers
var rect = document.getElementById("rect");
rect.addEventListener("click", randRect);
var oval = document.getElementById("oval");
oval.addEventListener("click", randOval);
function randomizeColor() {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * letters.length)];
}
return color;
}
function randomizeRectangle() {
var width = Math.random() * 700 + 50;
var height = Math.random() * 250 + 50;
if (height <= 20) {
height = 20;
}
var posX = Math.round(Math.random() * window.innerWidth);
var posY = Math.round(Math.random() * window.innerHeight);
var randomRecObj = {
"width": width + "px",
"height": height + "px",
"posX": posX,
"posY": posY
};
return randomRecObj;
}
function makeShape() {
var rect = randomizeRectangle();
var rectDOM = document.createElement("div");
rectDOM.className = "rectangle";
rectDOM.style.border = "1px solid black";
rectDOM.style.width = rect.width;
rectDOM.style.height = rect.height;
rectDOM.style.background = randomizeColor();
rectDOM.style.top = rect.posY + "px";
rectDOM.style.left = rect.posX + "px";
//rectDOM.addEventListener("click", selectShape);
// rectDOM.style.transform =rect.rotation;
return rectDOM;
}
function randRect() {
var rectDOM = makeShape();
var canvas = document.getElementById("canvas");
canvas.appendChild(rectDOM);
}
function randOval() {
var ovalDOM = makeShape();
ovalDOM.style.borderRadius = "50%";
var canvas = document.getElementById("canvas");
canvas.appendChild(ovalDOM);
}
function changeColor(){
}
function cancelSelection() {
var selected = document.getElementsByClassName("selected");
while (selected) {
selected[0].classList.remove(selected[0]);
}
}
function removeShape(event) {
var selectedShapes = document.getElementsByClassName("selected");
var len = selectedShapes.length;
while (len > 0) {
selectedShapes[0].parentNode.removeChild(selectedShapes[0]);
--len;
}
}
function removeCorners(rectDom) {
var corners = document.getElementsByClassName("corners");
var len = corners.length;
while (len > 0) {
corners[0].classList.remove("corners");
--len;
}
}
.header{
background: #4ABDAC;
color: #fff;
margin: 1px;
}
hr{
border-top: 3px double #2a3132;
}
ul{
list-style: none;
margin: 0;
padding: 0;
overflow: hidden;
background-color: #90afc5;
}
li{
float: left;
border: 2px solid #336b87;
padding: 3px;
margin: 3px;
}
li>a{
display: block;
color: #2a3132;
text-decoration: none;
padding: 10px 14px;
}
#color{
margin-left: 150px;
}
#rect{
margin-left: 100px;
}
li>a:hover{
color: #763626;
cursor: pointer;
}
#canvas{
background: #66a5ad;
position: relative;
height: 1200px;
width: 100%;
}
.corners{
position: absolute;
height: 10px;
width: 10px;
background:#fff;
border: 1px solid black;
display: none;
}
.selected .corners{
display: inline-block;
}
.cornerUpLeft{
top: -5px;
left: -5px;
}
.cornerUpRight{
top: -5px;
right: -5px;
}
.cornerBtmLeft{
bottom: -5px;
left: -5px;
}
.cornerBtmRight{
bottom: -5px;
right: -5px;
}
.rectangle{
position: absolute;
}
.colorBox{
border: 1px solid black;
height: 20px;
width: 20px;
list-style: none;
}
<h1 class="header">Sketch Board</h1>
<div>
<ul class="toolbar">
<li id="load">Load</li>
<li id="save">Save</li>
<li id="rect">Rectangle</li>
<li id="oval">Oval</li>
</ul>
<hr>
</div>
<div class="canvas" id="canvas">
</div>

How to create this range bar using JavaScript?

.range {-moz-box-sizing: border-box;box-sizing: border-box;-webkit-background-clip: padding-box;background-clip: padding-box;vertical-align: top;outline: none;line-height: 1;-webkit-appearance: none;-webkit-border-radius: 4px;border-radius: 4px;border: none;height: 2px;-webkit-border-radius: 0;border-radius: 0;-webkit-border-radius: 3px;border-radius: 3px;background-image: -webkit-gradient(linear, left top, left bottom, from(#ddd), to(#ddd));background-image: -webkit-linear-gradient(#ddd, #ddd);background-image: -moz-linear-gradient(#50b1f9, #50b1f9);background-image: -o-linear-gradient(#ddd, #ddd);background-image: linear-gradient(#50b1f9,#50b1f9);background-position: left center;-webkit-background-size: 100% 2px;background-size: 100% 2px;background-repeat: no-repeat;overflow: hidden;height: 31px;}
.range::-moz-range-track {position: relative;border: none;background-color: #50b1f9;height: 2px;border-radius: 30px;box-shadow: none;top: 0;margin: 0;padding: 0;}
.range::-webkit-slider-thumb {cursor: pointer;-webkit-appearance: none;position: relative;height: 29px;width: 29px;background-color: #fff;border: 1px solid #ddd;-webkit-border-radius: 30px;border-radius: 30px;-webkit-box-shadow: none;box-shadow: none;top: 0;margin: 0;padding: 0;}
.range::-moz-range-thumb {cursor: pointer;position: relative;height: 15px;width: 15px;background-color:#fff;border: 1px solid #ddd;border-radius: 30px;box-shadow: none;margin: 0;padding: 0}
.range::-webkit-slider-thumb:before {position: absolute;top: 13px;right: 0px;left: -1024px;width: 1024px;height: 2px;background-color: #50b1f9;;content: '';margin: 0;padding: 0;}
.range:disabled {opacity: 0.3;cursor: default;pointer-events: none;}
<input type="range" class="range">
I have to make this range bar and when I slide the months will also change accordingly. I tried making it into css but for changing range I would need JavaScript.
var range = document.getElementById("range"),
progress = document.getElementById("progress"),
handle = document.getElementById("handle"),
valueBox = document.getElementById("value"),
movable = false,
offsetX = range.offsetLeft,
rangeWidth = range.offsetWidth,
handleWidth = handle.offsetWidth,
max = 100, left, mouseX, value;
function move(e) {
if ( movable === true ) {
left = e.clientX - offsetX;
handle.style.left = left - ( handleWidth / 2 ) + "px";
progress.style.width = left + "px";
if ( left >= rangeWidth ) {
handle.style.left = rangeWidth - ( handleWidth / 2 ) + "px";
progress.style.width = rangeWidth + "px";
} if ( left <= 0 ) {
handle.style.left = "-" + handleWidth / 2 + "px";
progress.style.width = "0px";
}
value = Number(parseFloat(progress.style.width) / ( rangeWidth / max )).toFixed(0);
valueBox.textContent = value;
}
};
function on(e) {
movable = true;
mouseX = e.clientX;
};
function off() {
movable = false;
};
handle.addEventListener("mousedown", on, false);
window.addEventListener("mousemove", move, false);
window.addEventListener("mouseup", off, false);
* { margin: 0; padding: 0; border: 0; outline: 0; }
body { background-color: #FF0000; }
#range {
width: 350px;
height: 14px;
background-color: #242424;
margin: 100px auto 15px;
border-radius: 50px;
position: relative;
}
#progress {
position: absolute;
top: 0;
left: 0;
height: 100%;
background-color: #00A79D;
border-radius: 50px;
}
#handle {
position: absolute;
top: -3px;
height: 20px;
width: 20px;
background-color: #eee;
border-radius: 50px;
cursor: pointer;
}
#handle:hover, #handle:active {
background-color: #ddd;
}
#value-box {
text-align: center;
font: 14px arial;
line-height: 35px;
color: #eee;
width: 170px;
height: 35px;
background-color: rgba(0, 0, 0, .2);
margin: auto;
border-radius: 2px;
}
<div id="range">
<div id="progress"></div>
<div id="handle"></div>
</div>
<div id="value-box">Range bar Value : <span id="value">0</span></div>
Check output in Snippet Also.
Finally Output :

Categories

Resources