so im making some vanilla js draggable modal boxes but i keep having trouble when it comes to the dragging.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="css/main.css">
<title>Me website mate</title>
</head>
<body>
<!--------------------------------------------------------------------------------------->
<button id="buttonone" class="button">click me</button>
<div id="boxone" class="box">
<div id="headerone" class="header">header
<div class="box-buttons">
<div id="box-close-one" class="operation-button" style="background-color: rgb(207, 9, 33);">×</div>
<div id="box-maximize" class="operation-button" style="background-color: rgb(248, 201, 27);">max</div>
<div id="box-minimize" class="operation-button" style="background-color: rgb(0, 104, 69);">min</div>
</div>
</div>
<div class="content">
content
</div>
<div class="resize"></div>
</div>
<!---------------------------------------------------------------------------------------->
<button id="buttontwo" class="button">click me</button>
<div id="boxtwo" class="box" style="left: 500px;">
<div id="headertwo" class="header">header
<div class="box-buttons">
<div id="box-close-two" class="operation-button" style="background-color: rgb(207, 9, 33);">×</div>
<div id="box-maximize" class="operation-button" style="background-color: rgb(248, 201, 27);">max</div>
<div id="box-minimize" class="operation-button" style="background-color: rgb(0, 104, 69);">min</div>
</div>
</div>
<div class="content">
content
</div>
<div class="resize"></div>
</div>
<script src="javaScript/main.js"></script>
</body>
</html>
the html has 2 buttons and 2 modal boxes each button opening the assigned box, each box had a close button that hides said modal box
.box{
/*display: none;*/
font-family: "Comic Sans MS", cursive, sans-serif;
font-size: 12px;
background-color: #666;
border: 1px solid #000;
position: absolute;
height: 280px;
width: 400px;
margin: 2px;
position: absolute;
left: 0px;
z-index: 9;
}
.header{
position: relative;
height: 32px;
line-height: 32px;
font-size: 1.2em;
vertical-align: middle;
padding: 0 8px 0 8px;
white-space: normal;
overflow: hidden;
background: rgb(69, 161, 211);/*69, 161(golden ratio), 211(prime)*/
cursor: grab;
position: initial;
}
.box-buttons{
position: absolute;
display: flex;
flex-direction: row-reverse;
right: 0em;
top: 0em;
}
.operation-button{
height: 31px;
width: 31px;
border: 1px solid black;
text-align: center;
cursor: pointer;
}
.content{
position: absolute;
width: 400px;
height: 248px;
}
some styling
const boxOne = document.querySelector("#boxone");
boxOne.style.display = "none";
const boxTwo = document.querySelector("#boxtwo");
boxTwo.style.display = "none";
/////
const buttonOne = document.querySelector("#buttonone");
const closeOne = document.querySelector("#box-close-one");
const headOne = document.querySelector("#headerone");
buttonOne.addEventListener("click", function open(e){
openBox(boxOne);
});
closeOne.addEventListener("click", function close(e){
closeBox(boxOne);
});
headOne.addEventListener("mousedown",function grab(e){
mouseDown(boxOne, headOne,e);
});
/////
const buttonTwo = document.querySelector("#buttontwo");
const closeTwo = document.querySelector("#box-close-two");
const headTwo = document.querySelector("#headertwo");
buttonTwo.addEventListener("click",function open(e){
openBox(boxTwo);
});
closeTwo.addEventListener("click",function close(e){
closeBox(boxTwo);
});
function mouseDown(B,H,i){
var box = B;
var head = H;
head.style.cursor = "grabbing";
window.addEventListener("mousemove",drag);
window.addEventListener("mouseup",drop);
var windowHeight = window.innerHeight;
var windowWidth =window.innerWidth;
let previousX = i.clientX;
let previousY = i.clientY;
function drag(i){
let currentX = previousX - i.clientX;
let currentY = previousY - i.clientY;
const bounds = box.getBoundingClientRect();
console.log(bounds);
box.style.left = bounds.left - currentX + "px";
box.style.top = bounds.top - currentY + "px";
previousX = i.clientX;
previousY = i.clientY;
}
function drop(){
head.style.cursor = "grab";
window.removeEventListener("mousemove",drag);
window.removeEventListener("mouseup",drop);
}
}
function openBox(rect){
if (rect.style.display === "none") {
rect.style.display = "block";
}
console.log("open");
}
function closeBox(rectClose){
if(rectClose.style.display !== "none"){
rectClose.style.display = "none";
}
console.log("close");
}
it opens and closes well but it seems to be having a lot of trouble when i try to drag it. it always seems to go to the bottom right of the screen for some reason. Ive tried this project before but only with a single box, the code for the single box worked great and dragged perfectly fine but when ive tried to copy the same instructions , it fails. ik that it my code rn is inefficient but rn its just a prototype. Ive tried console.log to trouble shoot it but when i do the same to the previous project which worked fine, the output of the console looks pretty much the same. i dont know if im missing something bc i am a beginner, ive never taken a class on JS, so i dont really know what to look for or how to properly debug this. I would really appreciate the help and if possible, i would like to keep it in vanilla JS for the practice.
so after some experimenting, i boiled the answer down to the fact that the box moved 2 pixels to the right and 2 pixels down plus the movement of my mouse. I know this because I printed out the bounds variable to the console and moving my mouse only up (with a straightedge) and to the side. im still not sure what causes this however i just added a "-2" to the box.style.left and box.style.top to mitigate this problem so now the code is
box.style.left = (bounds.left - currentX) - 2 + "px";
box.style.top = (bounds.top - currentY) -2 + "px";
thank you to anybody that actually tired to figure it out and help me
Related
Good day,
I've came across the following CodePen from Estelle Pasquin. I would like to add this Apple-like scroll effect to my website.
Getting this to work on my site is no problem. However I would like to place content above this animation and this is where the problem comes in.
Based on the above CodePen content is structured like this:
<div class="intro mac"></div>
<div id="mac" class="mac"></div>
<div class="content">
<h2>Heading</h2>
<p>Content here</p>
</div>
However I need additional content above this animation section, like:
<div class="contentOne">
<h2>Heading 1</h2>
<p>Content here</p>
</div>
<div class="animationContent">
<div class="intro mac"></div>
<div id="mac" class="mac"></div>
</div>
<div class="content">
<h2>Heading 2 </h2>
<p>More content here</p>
</div>
In other words:
User scrolls through website content
User gets to a content break section where they see this big image, scroll, see the nice animation
User continues scrolling through rest of site
However this existing code only works when placed at the top of the page. Like a hero image.
In the JS file is can see the following variable declarations:
var $window = $(window);
var $intro = $('.intro');
var $mac = $('#mac');
var $h1 = $('h1');
My attempt
Looking at
var $window = $(window);
I can see the scroll is set on the window size. However I was thinking can't this be changed to a div. For example
var $window = $('#animationContent');
I would like this animation to work exactly as is just within a div placed on the page as opposed to being the first piece of content.
$(function() {
// cache all elements before we do anything
var $window = $(window);
var $intro = $('.intro');
var $mac = $('#mac');
var $h1 = $('h1');
// define variables and prefill
var offset = $mac.offset();
var windowHeight = $window.height();
var windowTop = $window.scrollTop();
var scrollPercent = (offset.top - windowTop) / offset.top;
var scale = 'scale(' + scrollPercent + ')';
// listen to scroll
$window.on('scroll', function() {
windowTop = $window.scrollTop();
// hide intro if point is reached
if (windowTop >= 940) {
$intro.hide();
} else {
if (windowTop < 200 && windowTop > 100) {
// only perform in a 100px range
$h1.fadeOut(500);
}
$intro.show();
scrollPercent = (offset.top - windowTop) / offset.top;
scale = 'scale(' + scrollPercent + ')';
$intro.css({
'transform': scale
});
}
});
});
#import url(https://fonts.googleapis.com/css?family=Open+Sans:400,700,800);
body {
color: #333;
font-family: Open sans;
}
h1 {
position: fixed;
top: 50%;
transform: translateY(-50%);
width: 100%;
text-align: center;
font-size: 52px;
z-index: 999;
color: rgba(255, 255, 255, 0.3);
}
.mac {
height: 613px;
width: 764px;
margin: 1340px auto 100px;
background: white url("https://i.imgur.com/AyELvGR.jpg") no-repeat 0 0;
background-size: 764px 613px;
backface-visibility: hidden;
}
.mac.intro {
position: fixed;
width: 2548px;
height: 2052px;
background-size: 100% auto;
margin: 0;
top: 0;
left: 50%;
margin-top: -300px;
margin-left: -1274px;
transform-origin: 50%;
}
.content {
width: 500px;
margin: 0 auto 150px;
}
.content h2 {
font-size: 52px;
line-height: 1.0865;
font-weight: 300;
margin-bottom: 48px;
}
.content p {
font-size: 18px;
margin: 1em 0 0 0;
line-height: 1.8;
color: #555;
font-weight: 400;
}
.content p a {
color: #555;
text-decoration: underline;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<h1>Just scroll!</h1>
<div class="intro mac"></div>
<div id="mac" class="mac"></div>
<div class="content">
<h2>Apple iMac scrolling effect.</h2>
<p>
iMac 27" mockup by Koy Carraway.<br/> Picture from WallWideHD - Transfagarasan.<br/> Read more about Transfagarasan <a href="http://en.wikipedia.org/wiki/Transf%C4%83g%C4%83r%C4%83%C8%99an"
target="_blank">here</a>.
</p>
</div>
If you take a look at KIOSK WEBSITE HERE they have the 'WE ARE OPEN" circular type in javascript (I know how to do that) but what I don't know is how to achieve that when scrolling. Like how does the text move when scrolling up or down. How do you get that in HTML/CSS/JS ?
View the code I worked on here https://codepen.io/noel_emmanuel/pen/WJxRZW
HTML:
<!--just a container used to position in the page-->
<div class="container">
<!--the holders/targets for the text, reuse as desired-->
<div class="circTxt" id="test"></div>
</div>
<!--I told you it was simple! :)-->
CSS:
body {
background: #111;
}
.container {
/*centers in the container*/
text-align: center;
}
div.circTxt {
/*allows for centering*/
display: inline-block;
/*adjust as needed*/
margin-bottom: 128px;
color: whitesmoke;
}
JS:
function circularText(txt, radius, classIndex) {
txt = txt.split(""),
classIndex = document.getElementsByClassName("circTxt")[classIndex];
var deg = 360 / txt.length,
origin = 0;
txt.forEach((ea) => {
ea = `<p style='height:${radius}px;position:absolute;transform:rotate(${origin}deg);transform-origin:0 100%'>${ea}</p>`;
classIndex.innerHTML += ea;
origin += deg;
});
}
circularText("WE ARE OPEN", 100, 0);
OPEN FOR SUGGESTIONS.
You could rotate this on a scroll event. This simply rotates the div depending on how far from the top of the page you have scrolled.
I added a height and width to the text, as well as positioned it fixed to see the effect.
function circularText(txt, radius, classIndex) {
txt = txt.split(""),
classIndex = document.getElementsByClassName("circTxt")[classIndex];
var deg = 360 / txt.length,
origin = 0;
txt.forEach((ea) => {
ea = `<p style='height:${radius}px;position:absolute;transform:rotate(${origin}deg);transform-origin:0 100%'>${ea}</p>`;
classIndex.innerHTML += ea;
origin += deg;
});
}
circularText("WE ARE OPEN", 100, 0);
$(document).ready(function(){
$(window).scroll(function(e){
rotateText();
});
function rotateText(){
var scrolled = $(window).scrollTop();
$('div.circTxt').css('transform','rotate('+scrolled+'deg)');
}
});
body {
background: #111;
}
.container {
/*centers in the container*/
text-align: center;
height: 4000px;
}
div.circTxt {
/*allows for centering*/
display: inline-block;
/*adjust as needed*/
margin-bottom: 128px;
color: whitesmoke;
position: fixed;
height: 200px;
width: 200px;
transform-origin: 0% 59%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!--just a container used to position in the page-->
<div class="container">
<!--the holders/targets for the text, reuse as desired-->
<div class="circTxt" id="test"></div>
</div>
<!--I told you it was simple! :)-->
I am currently building a form with Material Design Lite.
My form is similar to this one. A discrete slider, with a teardrop label, would then be the best solution for easily defining parts of an amount in my form.
But MDL doesn't include a slider with a teardrop label by default. Angular Material includes one, though.
How can I include a teardrop label similar to the one in the Material Design Guidelines ?
You can make a MDL continuous slider into a discrete slider by adding a step attribute. Ex. step="10".
As for the teardrop label, that's a bit harder. MDL doesn't have an built-in style for that so you'd need to add it yourself. The following should get you started.
Note: the calculation for the positioning (labelPosX) is a bit wonky and I'm sure a few minutes thinking about it would clean it up.
Demo
const demoInput = document.getElementById('demo');
const labelMaker = function (e) {
const input = e.target || e;
const label = input.parentElement.querySelectorAll('.label')[0] || document.createElement('div');
const labelInner = label.firstChild || document.createElement('div');
const parentWidth = input.parentElement.offsetWidth;
const inputWidth = input.offsetWidth ;
const labelOffset = (parentWidth - inputWidth) / 2;
const labelPosX = inputWidth * (input.value/100) + ((100 - input.value) * 14)/100;
label.classList.add('label');
if (input.value == 0) {
label.classList.add('zeroed');
} else {
label.classList.remove('zeroed');
}
labelInner.innerText = input.value;
label.appendChild(labelInner);
label.style.left = labelPosX + 'px';
input.parentElement.appendChild(label);
}
demoInput.addEventListener('input', labelMaker);
window.onload = function() {
labelMaker(demoInput)
};
body {
padding: 100px 0 0 0;
}
.label {
display: block;
position: absolute;
top: -55px;
width: 25px;
height: 25px;
border-radius: 0 50% 50% 50%;
background-color: rgb(63, 81, 181);
transform: rotate(-135deg);
margin-top: 20px;
}
.label div {
line-height: 25px;
color: #ffffff;
font-size: 10px;
font-weight: 300;
letter-spacing: 1px;
text-align: center;
transform: rotate(135deg);
}
.label.zeroed {
background-color: rgba(0, 0, 0, 0.3);
}
<script src="https://code.getmdl.io/1.3.0/material.min.js"></script>
<link href="https://code.getmdl.io/1.3.0/material.indigo-pink.min.css" rel="stylesheet" />
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--12-col">
<input class="mdl-slider mdl-js-slider" type="range" min="0" max="100" value="20" tabindex="0" step="10" id="demo">
</div>
</div>
I'm trying to create a mouse in and out effect that shows and disappears DIV's according to the mouse function. I've successfully done this, but the mouseout function flickers on and off when im inside the div instead of staying on.
Heres my sample code:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Kow Your Face</title>
<style>
#face {
background-image: url(face.png);
width: 262px;
height: 262px;
}
#lefteye {
background-image: url(circle.png);
width: 28px;
height: 28px;
position: relative;
top: 69px;
left: 59px;
}
#righteye {
background-image: url(circle.png);
width: 28px;
height: 28px;
position: relative;
top: 41px;
left: 167px;
}
#mouth {
background-image: url(circle.png);
width: 28px;
height: 28px;
position: relative;
top: 84px;
left: 114px;
}
</style>
</head>
<body>
<div id="face">
<div id="lefteye" onMouseOver="getElementById('lefteye').style.visibility='hidden'; getElementById('lefteyedes').style.visibility='visible';" onMouseOut="getElementById('lefteye').style.visibility='visible'; getElementById('lefteyedes').style.visibility='hidden';">
</div>
<div id="righteye" onMouseOver="getElementById('righteye').style.visibility='hidden'; getElementById('righteyedes').style.visibility='visible';" onMouseOut="getElementById('righteye').style.visibility='visible'; getElementById('righteyedes').style.visibility='hidden';">
</div>
<div id="mouth" onMouseOver="getElementById('mouth').style.visibility='hidden'; getElementById('mouthdes').style.visibility='visible';" onMouseOut="getElementById('mouth').style.visibility='visible'; getElementById('mouthdes').style.visibility='hidden';">
</div>
</div>
<div id="lefteyedes" style="visibility: hidden;">
<p>Left Eye</p>
</div>
<div id="righteyedes" style="visibility: hidden;">
<p>Right Eye</p>
</div>
<div id="mouthdes" style="visibility: hidden;">
<p>Mouth</p>
</div>
</body>
</html>
Use document.getElementById instead of just getElementById and you can use this keyword to refer to the current element:
<div id="lefteye" onMouseOver="this.style.visibility='hidden'; document.getElementById('lefteyedes').style.visibility='visible';" onMouseOut="this.style.visibility='visible'; document.getElementById('lefteyedes').style.visibility='hidden';">
</div>
For some reason your onmouseout function is being repeatedly called "onmousemove"...this solution should help you suppress the onmouseout function being repeatedly called. I've rewritten your code a little to help make it easier to enforce changes later (illustrated with one of the onmouseover/onmouseout pairs)...give this a shot:
<script type="text/javascript">
function leftEyeVisibility(vis1, vis2) {
//this function should work for the left eye when the left eye is hidden (lefteyedes is visible) and the mouse is moving over (or not moving at all) the hidden left eye div but has not moused out of it
var dg = document.getElementById("lefteye");
var divStyle = window.getComputedStyle(dg, "");
var mousePosition = function (e) {
var xCoord = e.pageX;
var yCoord = e.pageY;
return xCoord + "," + yCoord;
}
var positionArray = mousePosition.split(","); //split the xy coordinates returned by previous function
if ((positionArray[0] > dg.offsetLeft) && (positionArray[0] < dg.offsetLeft + dg.offsetWidth) && (positionArray[1] > dg.offsetTop) && (positionArray[1] < dg.offsetTop + dg.offsetHeight)) {
var mouseOverlap = 'yes';
} else var mouseOverlap = 'no';
if ((divStyle.visibility === 'hidden') && (mouseOverlap === 'yes')) {
return false;
} else {
document.getElementById("lefteye").style.visibility = vis1;
document.getElementById("lefteyedes").style.visibility = vis2;
}
}
</script>
<div id="lefteye" onmouseover="leftEyeVisibility('hidden', 'visible')" onmouseout="leftEyeVisibility('visible', 'hidden')">
</div>
With jQuery it would be much easier to do this...let me know if it works.
I am new to JavaScript/CSS (basically the whole world of web dev) and I am really struggling to create the following widget. I created a picture of what I want to make to make it more clear.
The Play/Pause and Stop button are ready. Loop checkbox is no problem. But the progress bar is painful. The two markers are supposed to mark the point from where the file would start playing and where it would stop. The progress bar is also supposed to be click-able, so if I want to access a certain point in time, then its possible.
What I tried so far
jQuery UI slider: For a sliding progress bar and use that draggable slider to access a certain point in audio file. Works fine. But no markers and looks really ugly. Don't how to change it.
<progress> tag: not very flexible. Marker? Clicking?
<div> tag: there seems to be no way to get the point where I clicked.
So, what do you guys recommend? How should I proceed?
Canvas Alternative
You might want to use a canvas and draw your own progress bar element within it.
Here are some canvas progress bar tutorials:
How to create a progress bar with HTML5
A progress bar using HTML5 canvas
Doing it with <progress>
To access the clicked position within a DOMElement, you can proceed with the click event's properties: clientX and clientY (MDN Source), like so:
HTML
<div class="marker" id="StartMarker">^</div>
<div class="marker" id="StopMarker">^</div>
<progress id="progress" value="0" min="0" max="100">0%</progress>
<form id="choice">
<button id="marker1">Beginning marker</button>
<button id="marker2">Ending marker</button>
<input type="hidden" id="markerValue" value="0" />
</form>
JavaScript (not optimized)
document.getElementById('progress').onclick = function (event, element) {
/* Math.floor((event.offsetX / this.offsetWidth) * 100) */
var newProgress = event.offsetX;
document.getElementById('choice').style.display = "block";
document.getElementById('markerValue').setAttribute('value', newProgress);
document.getElementById('marker1').onclick = function (event) {
event.preventDefault();
var newProgress = document.getElementById('markerValue').value;
var progressBar = document.getElementById('progress');
var startMarker = document.getElementById('StartMarker');
var stopMarker = document.getElementById('StopMarker');
var marker = startMarker;
marker.style.display = "block";
startMarker.style.display = "block";
startMarker.offsetTop = (progressBar.offsetTop + progressBar.offsetHeight + 2) + "px";
startMarker.style.left = newProgress + "px";
};
document.getElementById('marker2').onclick = function (event) {
event.preventDefault();
var newProgress = document.getElementById('markerValue').value;
var progressBar = document.getElementById('progress');
var startMarker = document.getElementById('StartMarker');
var stopMarker = document.getElementById('StopMarker');
stopMarker.style.display = "block";
stopMarker.offsetTop = (progressBar.offsetTop + progressBar.offsetHeight + 2) + "px";
stopMarker.style.left = newProgress + "px";
};
};
CSS
.marker {
position:absolute;
top:24px;
left:9px;
display:none;
z-index:8;
font-weight:bold;
text-align:center;
}
#StartMarker {
color: #CF0;
}
#StopMarker {
color:#F00;
}
#choice {
display:none;
}
progress {
display: inline-block;
-moz-box-sizing: border-box;
box-sizing: border-box;
width: 300px;
height: 20px;
padding: 3px 3px 2px 3px;
background: #333;
background: -webkit-linear-gradient(#2d2d2d, #444);
background: -moz-linear-gradient(#2d2d2d, #444);
background: -o-linear-gradient(#2d2d2d, #444);
background: linear-gradient(#2d2d2d, #444);
border: 1px solid rgba(0, 0, 0, .5);
border-radius: 15px;
box-shadow: 0 1px 0 rgba(255, 255, 255, .2);
}
Live Demo
Using simple blocks for that is possible. Your layout would look like this (simplified):
HTML
<div class="progressbar">
<div class="bar">
<div class="progress" style="width: 30%;">
</div>
</div>
<div class="markers">
<div class="right" style="width: 70%;">
<div class="marker">
</div>
<div class="left" style="width: 20%;">
<div class="marker">
</div>
</div>
</div>
</div>
</div>
SCSS
.progressbar {
width: 20em;
background: grey;
.bar {
height: 2em;
.progress {
background: blue;
height: 100%;
}
}
.markers {
height: 1em;
background: white;
.right {
height: 100%;
background: red;
.marker {
width: 1em;
height: 100%;
background: green;
position: relative;
float: right;
}
.left {
background: white;
height: 100%;
}
}
}
}
The operations can be quite difficult
jQuery
$('.bar').click(function(e){
$(this).find('.progress').css('width', (e.offsetX / this.offsetWidth)*100+'%');
});
will set the Progressbar properly on clicks.
For the markers though you will need mousedown, mousemove, mouseleave events, since you got 2 of them.
Example
http://jsfiddle.net/JXauW/