I've been battling this for quite some time and I'm not having much luck, it always gets repositioned all over the place!
I essentially want my control to center this component in the middle of the page. I also want to rotate flip it(3d) around it's center axis(Y or X, doesn't matter) but I'm having no luck with the first step which is just getting it to the center.
<div className="note-container">
<div className="note"
style={Object.assign({}, note.position) }>
<p>{note.text}</p>
<span>
<button onClick={() => onExpand(note.id) }
className="btn btn-warning glyphicon glyphicon-resize-full"/>
<button onClick={() => onEdit(note.id) }
className="btn btn-primary glyphicon glyphicon-pencil"/>
<button onClick={onRemove}
className="btn btn-danger glyphicon glyphicon-trash"/>
</span>
</div>
</div>
The function I'm calling to reposition it to the center is function onExpand(noteId){...}
Here is the CSS for .note-container and .note
div.note-container {
position: fixed;
top: 5%;
left: 90%;
}
div.note {
height: 150px;
width: 150px;
background-color: yellow;
margin: 2px 0;
position: relative;
cursor: -webkit-grab;
-webkit-box-shadow: 5px 5px 15px 0 rgba(0, 0, 0, .2);
box-shadow: 5px 5px 15px 0 rgba(0, 0, 0, .2);
}
div.note:active {
cursor: -webkit-grabbing;
}
div.note p {
font-size: 22px;
padding: 5px;
font-family: "Shadows Into Light", Arial;
}
div.note div.back p {
font-size: 30px;
padding: 5px;
font-family: "Shadows Into Light", Arial;
}
div.note:hover> span {
opacity: 1;
}
div.note> span {
position: absolute;
bottom: 2px;
right: 2px;
opacity: 0;
transition: opacity .25s linear;
}
div.note button {
margin: 2px;
}
div.note> textarea {
height: 75%;
background: rgba(255, 255, 255, .5);
}
And here is the onExpand function
onExpand(noteId) {
//This needs a lot of work....
event.preventDefault();
let flippedNote = this.props.notes
.filter(note => note.id === noteId)[0];
flippedNote.position.transition = "1.0s";
flippedNote.position.transformStyle = "preserve-3d";
flippedNote.position.backgroundColor = "#3498db";
flippedNote.position.color = "white";
flippedNote.position.width = "300px";
flippedNote.position.height = "300px";
flippedNote.position.position = "absolute";
flippedNote.position.right = `50% -${flippedNote.position.width / 2}px`;
flippedNote.position.top = `50% -${flippedNote.position.height / 2}px`;
// flippedNote.position.transform = "translate(-50%, -50%) rotateY(180deg)";
this.setState({/*Stuff later... */});
}
Also when I render the note on the page I assign it a random location on the page based on this logic(this is what is initially passed into the style attribute in the div.note element:
position: {
right: randomBetween(0, window.innerWidth - 150) + "px",
top: randomBetween(0, window.innerHeight - 150) + "px",
transform: "rotate(" + randomBetween(-15, 15) + "deg)"
}
Here is what the html on the page looks like(note I am also dragging the sticky note across the page using transform: translate(...).
try this:
div.note
{
position: relative;
width: 150px;
left: 0;
right: 0;
margin: 2px auto;
}
To control the position, you can set position: relative; or position: absolute; on your div.note.
Alternatively, this can be done by manipulating margins, but it's not really a good way.
You can test your code manually by opening the page in browser and manipulating CSS values through Chrome's developer tools.
Here is the final solution after working on it this weekend:
onExpand(noteId, currentNotePosition) {
event.preventDefault();
let note = this.props.notes
.filter(specificNote => specificNote.id === noteId)[0];
const centerOfWindow = {
left: window.innerWidth / 2,
top: window.innerHeight / 2
};
if (!note.centered) {
note.position.transition = "all 1s";
note.position.transformStyle = "preserve-3d";
note.position.backgroundColor = "#3498db";
note.position.color = "white";
note.position.width = "300px";
note.position.height = "300px";
note.position.zIndex = "100";
note.position.position = "relative";
const offset = {
x: 150,
y: 150
};
const translatedCoordinates = this.getCoordinateTarget(centerOfWindow, offset, currentNotePosition);
note.position.transform = `translate(${translatedCoordinates.x}px, ${translatedCoordinates.y}px) rotateY(180deg)`;
note.originalPosition = {
left: currentNotePosition.left,
top: currentNotePosition.top,
width: currentNotePosition.width,
movement: translatedCoordinates
};
note.centered = true;
} else {
note.position.backgroundColor = "yellow";
note.position.color = "black";
note.position.width = "150px";
note.position.height = "150px";
note.position.transform = "";
note.centered = false;
}
this.props.stickyNoteActions.repositionedNoteSuccess(Object.assign({}, note));
}
Related
I have a small page. Divas in the form of circles are created here every certain time.
They spawn in random places.
As can be seen even on the buttons and slightly outside the page.
The question is. Is it possible to make a box that does not touch the buttons, and that the circles are created within this box?
This should be done as a border with a certain extension, but specifying everything in pixels is not an option, it will be bad for different screens.
I created such a frame, replaced document.body.appendChild(div);
on the document.getElementById("spawnRadius").appendChild(div);
It seems that they should appear within this frame, but no, all the same throughout the page.
I also tried instead of whole page height and width document.documentElement.clientWidth use the width and height of the desired border spawnRadius.width
But now all my circles do not appear randomly, but at the beginning of this block in one place.
I tried to see these values through console.log
console.log(documentHeight);
console.log(documentWidth);
But getting there undefined
PS. Demo watch in full page
//timer
var minutesLabel = document.getElementById("minutes");
var secondsLabel = document.getElementById("seconds");
var totalSeconds = 0;
setInterval(setTime, 1000);
function setTime() {
++totalSeconds;
secondsLabel.innerHTML = pad(totalSeconds % 60);
minutesLabel.innerHTML = pad(parseInt(totalSeconds / 60));
}
function pad(val) {
var valString = val + "";
if (valString.length < 2) {
return "0" + valString;
} else {
return valString;
}
}
//create circle
var widthHeight = 65;
var margin = 25;
var delta = widthHeight + margin;
var spawnRadius = document.getElementById("spawnRadius");
let clicks = 0;
function createDiv(id, color) {
let div = document.createElement('div');
var currentTop = 0;
var documentHeight = spawnRadius.height;
var documentWidth = spawnRadius.width;
div.setAttribute('class', id);
if (color === undefined) {
let colors = ['#35def2', '#35f242', '#b2f235', '#f2ad35', '#f24735', '#3554f2', '#8535f2', '#eb35f2', '#f2359b', '#f23547'];
div.style.borderColor = colors[Math.floor(Math.random() * colors.length)];
}
else {
div.style.borderColor = color;
}
div.classList.add("circle");
div.classList.add("animation");
currentTop = Math.floor(Math.random() * documentHeight) - delta;
currentLeft = Math.floor(Math.random() * documentWidth) - delta;
var limitedTop = Math.max(margin * -1, currentTop);
var limitedLeft = Math.max(margin * -1, currentLeft);
div.style.top = limitedTop + "px";
div.style.left = limitedLeft + "px";
const nodes = document.querySelectorAll('.animation');
for(let i = 0; i < nodes.length; i++) {
nodes[i].addEventListener('click', (event) => {
event.target.style.animation = 'Animation 200ms linear';
setTimeout(() => {
event.target.style.animation = '';
}, 220); });
}
$(div).click(function() {
$('#clicks').text(++clicks);
$(this).fadeOut();
});
document.getElementById("spawnRadius").appendChild(div);
}
let i = 0;
const oneSecond = 600;
setInterval(() => {
i += 1;
createDiv(`circle${i}`);
}, oneSecond);
html, body {
width: 100%;
height: 100%;
margin: 0;
background: #0f0f0f;
}
.back {
font-family: "Comic Sans MS", cursive, sans-serif;
font-size: 25px;
letter-spacing: 2px;
word-spacing: 2px;
color: #ffffff;
text-shadow: 0 0 5px #ffffff, 0 0 10px #ffffff, 0 0 20px #ffffff, 0 0 40px #ff00de, 0 0 80px #ff00de, 0 0 90px #ff00de, 0 0 100px #ff00de, 0 0 150px #ff00de;
font-weight: 700;
text-decoration: none;
font-style: italic;
font-variant: normal;
text-transform: lowercase;
position: absolute;
top: 25%;
left: 2%;
user-select: none;
z-index: 999;
}
.panel {
color: #0f0f0f;
font-size: 40px;
z-index: 999;
position: absolute;
cursor: default;
user-select: none;
color: #0f0f0f;
}
.score {
border: 1px solid #ffffff;
padding: 5px;
background-color: #ffffff;
border-radius: 40px 10px;
}
.time {
border: 1px solid #ffffff;
padding: 5px;
background-color: #ffffff;
border-radius: 40px 10px;
}
.circle {
width: 60px;
height: 60px;
border-radius: 60px;
background-color: #0f0f0f;
border: 3px solid #000;
margin: 20px;
position: absolute;
}
#keyframes Animation {
0% {
transform: scale(1);
}
50% {
transform: scale(.8);
}
100% {
transform: scale(1);
}
}
#spawnRadius {
top: 55%;
height: 650px;
width: 1000px;
left: 50%;
white-space: nowrap;
position: absolute;
transform: translate(-50%, -50%);
background: #0f0f0f;
border: 2px solid #ebc6df;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<span class="panel">
<span class="score">Score: <a id="clicks">0</a></span>
<span class="time">Time: <label id="minutes">00</label>:<label id="seconds">00</label></span>
</span>
back
<div id="spawnRadius"></div>
To answer your main question, the getBoundingClientRect method can be used to retrieve the current bounding rectangle of an element, using which you can determine where the valid spawn areas are.
When choosing a valid placement, only consider the width and height of the container element, since the coordinates of child elements are relative to its parent. You also need to take into account the size of the elements being spawned, so the valid range of the x position for example is 0 to containerWidth - circleWidth.
The circles also had a CSS margin associated with them, which would offset them past their absolute coordinates.
There are a few other issues with the code though which you may run into later on:
There was an odd mix of jQuery and standard JavaScript calls, so if you're familiar with native JavaScript methods then it's likely simpler to stick with those and remove the dependency on jQuery.
For example, there were two click event handlers on each circle, one to add the CSS animation and another to increment the score. These can be combined into a single function.
The bounce out animation and the jQuery fade out can also be combined by adding opacity values into the animation start and end keyframes.
There was a loop in the createDiv function which added another click event handler to every circle element rather than just to the newly created element. This may have originally necessitated the jQuery click handler outside of that loop, since otherwise the score counter would have been incremented multiple times.
It was also possible to click the circles multiple times before the animation was complete (hence adding multiple points), which was likely not intended. Adding a simple Boolean clicked flag can avoid this.
Once the fade animation completed, the circle element itself was still on the page, it just had a display of none so wouldn't be visible. Over time, this would cause slowdowns on lower end hardware since there would be many DOM elements still sitting in memory that were no longer required. As such, it's best to remove elements from the DOM once they're no longer needed using removeChild. You had the right idea by removing the animation after the animation completed.
Here's the amended code:
var minutesLabel = document.getElementById("minutes");
var secondsLabel = document.getElementById("seconds");
var clickEl = document.getElementById("clicks");
var totalSeconds = 0;
let clicks = 0;
setInterval(setTime, 1000);
function setTime() {
++totalSeconds;
secondsLabel.innerText = pad(totalSeconds % 60);
minutesLabel.innerText = pad(parseInt(totalSeconds / 60));
}
function pad(val) {
var valString = val + "";
if (valString.length < 2) {
return "0" + valString;
} else {
return valString;
}
}
var spawnRadius = document.getElementById("spawnRadius");
var spawnArea = spawnRadius.getBoundingClientRect();
const circleSize = 66; // Including borders
//create circle
function createDiv(id, color) {
let div = document.createElement('div');
div.setAttribute('class', id);
if (color === undefined) {
let colors = ['#35def2', '#35f242', '#b2f235', '#f2ad35', '#f24735', '#3554f2', '#8535f2', '#eb35f2', '#f2359b', '#f23547'];
div.style.borderColor = colors[Math.floor(Math.random() * colors.length)];
}
else {
div.style.borderColor = color;
}
// Randomly position circle within spawn area
div.style.top = `${Math.floor(Math.random() * (spawnArea.height - circleSize))}px`;
div.style.left = `${Math.floor(Math.random() * (spawnArea.width - circleSize))}px`;
div.classList.add("circle", "animation");
// Add click handler
let clicked = false;
div.addEventListener('click', (event) => {
if (clicked) { return; } // Only allow one click per circle
clicked = true;
div.style.animation = 'Animation 200ms linear forwards';
setTimeout(() => { spawnRadius.removeChild(div); }, 220);
clickEl.innerText = ++clicks
});
spawnRadius.appendChild(div);
}
let i = 0;
const oneSecond = 1000;
setInterval(() => {
i += 1;
createDiv(`circle${i}`);
}, oneSecond);
html, body {
width: 100%;
height: 100%;
margin: 0;
background: #0f0f0f;
}
.back {
font-family: "Comic Sans MS", cursive, sans-serif;
font-size: 25px;
letter-spacing: 2px;
word-spacing: 2px;
color: #ffffff;
text-shadow: 0 0 5px #ffffff, 0 0 10px #ffffff, 0 0 20px #ffffff, 0 0 40px #ff00de, 0 0 80px #ff00de, 0 0 90px #ff00de, 0 0 100px #ff00de, 0 0 150px #ff00de;
font-weight: 700;
text-decoration: none;
font-style: italic;
font-variant: normal;
text-transform: lowercase;
position: absolute;
top: 25%;
left: 2%;
user-select: none;
z-index: 999;
}
.panel {
color: #0f0f0f;
font-size: 40px;
z-index: 999;
position: absolute;
cursor: default;
user-select: none;
color: #0f0f0f;
}
.score {
border: 1px solid #ffffff;
padding: 5px;
background-color: #ffffff;
border-radius: 40px 10px;
}
.time {
border: 1px solid #ffffff;
padding: 5px;
background-color: #ffffff;
border-radius: 40px 10px;
}
.circle {
width: 60px;
height: 60px;
border-radius: 60px;
background-color: #0f0f0f;
border: 3px solid #000;
position: absolute;
}
#keyframes Animation {
0% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(.8);
}
100% {
transform: scale(1);
opacity: 0;
}
}
#spawnRadius {
top: 55%;
height: 650px;
width: 1000px;
left: 50%;
white-space: nowrap;
position: absolute;
transform: translate(-50%, -50%);
background: #0f0f0f;
border: 2px solid #ebc6df;
}
<span class="panel">
<span class="score">Score: <a id="clicks">0</a></span>
<span class="time">Time: <label id="minutes">00</label>:<label id="seconds">00</label></span>
</span>
back
<div id="spawnRadius"></div>
I'm trying recoding the https://www.orizon.co/ following dot. The code I've written to asure the dot rising effect when the pointer fly over some elements seems correct, but when the dot's z-index is higher than the flew over element's one, there is a kind of bug than make me crazy.
class CursorFollower {
constructor() {
this.follower = document.getElementById("cursor-follower");
this.topGap = 12;
this.leftGap = 4;
window.addEventListener("mousemove", this.follow.bind(this));
this.eventsSet();
}
// The function doing the dot follows the pointer
follow() {
setTimeout(function () {
cursorFollower.follower.style.left = (this.clientX - cursorFollower.topGap) + "px";
cursorFollower.follower.style.top = (this.clientY - cursorFollower.leftGap) + "px";
}.bind(window.event), 100);
}
eventsSet() {
// Adding events to button
var button = document.querySelector(".follower-over");
button.addEventListener("pointerenter", this.overOn.bind(this));
button.addEventListener("pointerleave", this.overOff.bind(this));
}
overOn() {
// The effects to apply when the pointer flies over the button
this.follower.style.opacity = 0.3;
this.follower.style.width = "50px";
this.follower.style.height = "50px";
this.follower.style.backgroundColor = "black";
this.topGap = 25;
this.leftGap = 25;
}
overOff() {
// The effects to apply when the pointer leave the button
this.follower.style.opacity = 1;
this.follower.style.width = "7px";
this.follower.style.height = "7px";
this.follower.style.backgroundColor = "rgba(42, 0, 212, 1)";
this.topGap = 12;
this.leftGap = 4;
}
}
let cursorFollower = new CursorFollower();
/* Some styling */
.contact-us{
padding: 25px 40px;
width: 200px;
display: flex;
align-items: center;
color: white;
background-color: #2b00d4 ;
height: 60px;
position: relative;
z-index: 1;
}
#cursor-follower{
z-index: 999;
position: fixed;
background-color: #2b00d4;
height: 7px;
width: 7px;
border-radius: 50%;
transition: opacity 0.3s , width 0.3s , height 0.3s, background-color 0.3s;
}
<div id="cursor-follower"></div>
<div class="contact-us follower-over">
<p>CONTACT US</p>
</div>
When the button's z-index is higher than the dot's one, the effects works. Else, it bugs
This is because your follower element is getting under cursor, triggering overOff than when its shrinks it triggers overOn and so on.
The simplest solution is to add pointer-events: none; into the follower so it doesn't trigger overOn/overOff:
class CursorFollower {
constructor() {
this.follower = document.getElementById("cursor-follower");
this.topGap = 12;
this.leftGap = 4;
window.addEventListener("mousemove", this.follow.bind(this));
this.eventsSet();
}
// The function doing the dot follows the pointer
follow() {
setTimeout(function() {
cursorFollower.follower.style.left = (this.clientX - cursorFollower.topGap) + "px";
cursorFollower.follower.style.top = (this.clientY - cursorFollower.leftGap) + "px";
}.bind(window.event), 100);
}
eventsSet() {
// Adding events to button
var button = document.querySelector(".follower-over");
button.addEventListener("pointerenter", this.overOn.bind(this));
button.addEventListener("pointerleave", this.overOff.bind(this));
}
overOn() {
// The effects to apply when the pointer flies over the button
this.follower.style.opacity = 0.3;
this.follower.style.width = "50px";
this.follower.style.height = "50px";
this.follower.style.backgroundColor = "black";
this.topGap = 25;
this.leftGap = 25;
}
overOff() {
// The effects to apply when the pointer leave the button
this.follower.style.opacity = 1;
this.follower.style.width = "7px";
this.follower.style.height = "7px";
this.follower.style.backgroundColor = "rgba(42, 0, 212, 1)";
this.topGap = 12;
this.leftGap = 4;
}
}
let cursorFollower = new CursorFollower();
/* Some styling */
.contact-us {
padding: 25px 40px;
width: 200px;
display: flex;
align-items: center;
color: white;
background-color: #2b00d4;
height: 60px;
position: relative;
z-index: 1;
}
#cursor-follower {
pointer-events: none; /* added */
z-index: 999;
position: fixed;
background-color: #2b00d4;
height: 7px;
width: 7px;
border-radius: 50%;
transition: opacity 0.3s, width 0.3s, height 0.3s, background-color 0.3s;
}
<div id="cursor-follower"></div>
<div class="contact-us follower-over">
<p>CONTACT US</p>
</div>
However there is even simpler solution with much less javascript:
window.addEventListener("mousemove", e => {
setTimeout(s => {
document.documentElement.style.setProperty("--cursorX", e.clientX + "px");
document.documentElement.style.setProperty("--cursorY", e.clientY + "px");
}, 100);
});
/* Some styling */
:root
{
--cursorX: -100px;
--cursorY: -100px;
}
.contact-us {
padding: 25px 40px;
width: 100px;
display: flex;
align-items: center;
color: white;
background-color: #2b00d4;
height: 40px;
position: relative;
z-index: 1;
}
.cursor-follower {
--size: 7px;
--gapLeft: 12px;
--gapTop: 4px;
pointer-events: none;
position: fixed;
background-color: #2b00d4;
width: var(--size);
height: var(--size);
border-radius: 50%;
transition: opacity 0.3s, width 0.3s, height 0.3s, background-color 0.3s;
top: calc(var(--cursorY) - var(--gapTop));
left: calc(var(--cursorX) - var(--gapLeft));
}
.follower-over:hover~.cursor-follower {
--size: 50px;
--gapLeft: 25px;
--gapTop: 25px;
opacity: 0.3;
background-color: black;
z-index: 2;
}
/* extra */
.follower-over.green:hover~.cursor-follower {
background-color: green;
opacity: 0.7;
--size: 80px;
--gapLeft: 40px;
--gapTop: 40px;
}
.contact-us:not(.follower-over) {
background-color: pink;
}
.contact-us {
display: inline-block;
margin: 1em;
}
<div class="contact-us follower-over">
<p>CONTACT US</p>
</div>
<div class="contact-us follower-over">
<p>Another button</p>
</div>
<div class="contact-us">
<p>No follower</p>
</div>
<div class="contact-us follower-over green">
<p>Large green</p>
</div>
<div class="cursor-follower"></div>
The only caveat with this method is the .cursor-follower must be last element and has the same parent as all .follower-over elements
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>
I am in a class that is writing an online UNO game (this is not a graded assignment, just a class project). I am currently trying to develop the functionality to play a card. Basically, the player needs to be able to click on a card in their hand and have it appear in the discard pile. I thought about animating this, but we have 1 week left and a lot to get done, so my idea is to just have the player double-click on the card and it will appear in the discard pile.
Each of the cards in all the players' hands are separate divs created in javascript via information from the back end. I do not, however, have the code connected to the back end yet because I need to be able to test my functions and script now. Thus I have currently hard-coded the cards.
The discard pile has one card on it. I have determined that we don't actually need every single card to be placed on the discard pile. Rather, it should be enough to change the color and the rank of the card on the discard pile to reflect the card discarded and just eliminate that div from the player's hand. If you think I am wrong about this, please tell me.
That is where my problem is. I have a bit of script here that is supposed to erase the color of the discard pile card and replace it with the color of the div card that was clicked on in the player's hand. Here is the code (full code posted later in the post):
/*
The double-click on the card in the player's hand does erase the color from the discard pile card, but it doesn't add the color of the card from the hand to the discard pile card. I have tried different variations of the code, but none seem to work. Can anyone help me? Or am I thinking about this the wrong way?
*/
$(document).ready(function() {
function playCardThisPlayer(game) {
currCardColor = $(this).color;
$(".card").dblclick(function() {
$(".discardPile").removeClass(game.discardPile.color);
$(".discardPile").addClass.$(currCardColor);
});
}
playCardThisPlayer(gameTurn);
var gameTurn = {
deckCount: 40,
discardPile: {
color: "yellow",
rank: "2"
},
players: [{
name: "David", //players[0].name
hand: [{
color: "yellow",
rank: "3"
},
{
color: "blue",
rank: "3"
},
{
color: "red",
rank: "4"
},
{
color: "black",
rank: "w"
},
{
color: "blue",
rank: "7"
},
{
color: "blue",
rank: "8"
},
{
color: "green",
rank: "S"
}
]
},
{
name: "Dan", //players[1].name
hand: 4 //players[1].hand
},
{
name: "John", //players[2].name
hand: 5 //players[2].hand
},
{
name: "Kent", //players[3].name
hand: 10 //players[3].hand
},
{
name: "Amy",
hand: 15
}
]
};
function makePlayerList(game) {
for (i = 0; i < game.players.length; i++) {
$(".list").append("<p>" + (i + 1) + ". " + game.players[i].name + "</p>");
}
}
makePlayerList(gameTurn);
function createCards(game) {
var currPlayer = game.players[0];
var hand = $("<div class='hand'></div>");
for (var i = 0; i < currPlayer.hand.length; i++) {
var card = $("<div class='card'></div>" /*<div class='playerLabel'></div>"*/ );
card.addClass(".oval-shape");
var corner1 = $("<div></div>");
var middle = $("<div></div>");
var corner2 = $("<div></div>");
var oval = $("<div></div>")
corner1.append(currPlayer.hand[i].rank);
corner1.addClass("corner1");
middle.append(currPlayer.hand[i].rank);
middle.addClass("middle");
oval.addClass("oval-shape");
card.append(oval);
corner2.append(currPlayer.hand[i].rank);
corner2.addClass("corner2");
card.append(corner1);
card.append(middle);
card.append(corner2);
card.addClass(currPlayer.hand[i].color);
hand.append(card);
}
$("#table").append(hand);
}
function createCardBacks(game) {
for (var i = 1; i < game.players.length; i++) {
var hand = $("<div class='hand'></div>");
for (var j = 0; j < game.players[i].hand; j++) {
var cardBack = $("<div class='cardBack black'></div>");
var oval = $("<div></div>")
oval.addClass("oval-shape");
cardBack.append(oval);
hand.append(cardBack);
}
$("#table").append(hand);
}
}
function createDiscardPile(game) {
var topOfDiscardPile = $(".discardPile");
topOfDiscardPile.addClass(".oval-shape");
var corner1 = $("<div></div>");
var middle = $("<div></div>");
var corner2 = $("<div></div>");
var oval = $("<div></div>")
corner1.append(game.discardPile.rank);
corner1.addClass("corner1");
middle.append(game.discardPile.rank);
middle.addClass("middle");
oval.addClass("oval-shape");
topOfDiscardPile.append(oval);
corner2.append(game.discardPile.rank);
corner2.addClass("corner2");
topOfDiscardPile.append(corner1);
topOfDiscardPile.append(middle);
topOfDiscardPile.append(corner2);
topOfDiscardPile.addClass(game.discardPile.color);
}
createCards(gameTurn);
createCardBacks(gameTurn);
createDiscardPile(gameTurn);
function playCardThisPlayer(game) {
currCardColor = $(this).color;
$(".card").dblclick(function() {
$(".discardPile").removeClass(game.discardPile.color);
$(".discardPile").addClass.$(currCardColor);
});
}
playCardThisPlayer(gameTurn);
function fan(container, angle) {
var num = $(container).children().length;
var rotate = -angle * Math.floor(num / 2);
$(container).children().each(function() {
$(this).data("rotate", rotate);
$(this).css("transform", "translate(-50%,0) rotate(" + rotate + "deg)");
$(this).css("transform-origin", "0 100%");
rotate += angle;
});
$(container).children().mouseenter(function() {
var rotate = parseInt($(this).data("rotate")) * Math.PI / 180;
$(this).css("top", (-3 * Math.cos(rotate)) + "vmin");
$(this).css("left", (3 * Math.sin(rotate)) + "vmin");
});
$(container).children().mouseleave(function() {
$(this).css("top", 0);
$(this).css("left", 0);
});
}
var rotate = 0;
var num = $("#table").children().length;
var angleInc = 360 / num;
$("#table").children().each(function(idx) {
$(this).css("transform", "rotate(" + rotate + "deg)");
$(this).append("<div class='playerLabel'><span>" + (idx + 1) + "</span></div>")
$(this).css("transform-origin", "50% -18vmin");
fan(this, (idx == 0) ? 7 : 2.5);
rotate += angleInc;
});
});
* {
margin: 0;
padding: 0;
}
body {
background: #00a651;
}
#table {
width: 100vmin;
height: 100vmin;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
background-color: #00FF00;
border-radius: 50%;
}
.card {
position: absolute;
top: 0;
left: 0;
display: inline-block;
}
.discardPile {
position: absolute;
bottom: 0;
left: 0;
display: inline-block;
}
.card,
.discardPile {
width: 15vmin;
height: 22vmin;
border-radius: 1vmin;
background: #fff;
-webkit-box-shadow: 3px 3px 7px rgba(0, 0, 0, 0.3);
box-shadow: 3px 3px 7px rgba(0, 0, 0, 0.3);
text-shadow: 2px 2px 0px #808080;
border: .3em solid white;
transition: all 0.125s;
}
.hand {
position: absolute;
left: 50%;
bottom: 10vmin;
width: 0;
height: 22vmin;
}
span {
position: absolute;
z-index: 100;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.playerLabel {
margin-top: -10vh;
background-color: red;
width: 3vmin;
height: 3vmin;
border: 1px solid black;
border-radius: 50%;
}
.list {
color: yellow;
font-family: 'Gloria Hallelujah', cursive;
font-size: 3vmin;
}
.yellow {
background-color: yellow;
}
.blue {
background-color: blue;
}
.red {
background-color: red;
}
.green {
background-color: green;
}
.black {
background-color: black;
}
.corner1 {
position: absolute;
font-size: 3.5vmin;
left: .5vmin;
top: .5vmin;
color: white;
}
.corner2 {
position: absolute;
font-size: 3.5vmin;
right: .5vmin;
bottom: .5vmin;
color: white;
}
.middle {
position: absolute;
font-size: 10vmin;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.oval-shape {
width: 10vmin;
height: 22vmin;
background: white;
border-radius: 7vmin / 15vmin;
transform: translate(-50%, -50%) rotate(25deg);
margin: 0 auto;
position: absolute;
left: 50%;
top: 50%;
}
.slide-out {
top: -3vmin;
}
.cardBack {
position: absolute;
top: 0;
display: inline-block;
width: 15vmin;
height: 22vmin;
border-radius: 1vmin;
-webkit-box-shadow: .3vmin .3vmin .7vmin rgba(0, 0, 0, 0.3);
box-shadow: .3vmin .3vmin .7vmin rgba(0, 0, 0, 0.3);
text-shadow: .2vmin .2vmin 0 #808080;
border: .3em solid white;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>UNO Cards</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://fonts.googleapis.com/css?family=Gloria+Hallelujah" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="style.css">
<script src="https://code.jquery.com/jquery-3.2.1.js" integrity="sha256-DZAnKJ/6XZ9si04Hgrsxu/8s717jcIzLy3oi35EouyE=" crossorigin="anonymous"></script>
</head>
<body>
<div class="list"></div>
<div class="discardPile"></div>
<div id="table"></div>
<script src="script.js"></script>
</body>
</html>
Thanks!
.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 :