We have to build a clock in JavaScript using divs only, (document.createElement()). Somehow, I never get the positioning of the divs right. Currently, I'm already struggling to make the first DIV.
Sorry if I have mistakes in the calculation of the angles.
Are there any better ways to achieve this goal?
Now it looks a bit like this:
The red lines are representing the numbers of a clock (12 of them in total).
window.onload = function drawclock() {
var clock = this.document.getElementById("clock");
var width = clock.offsetHeight;
var radius = width / 2;
for (var i = 1; i < 12; i++) {
var element = document.createElement("DIV");
addClass(element, "h");
addClass(element, i);
var deg = 30 * i;
var x = Math.cos(deg * (180 / Math.PI)) * radius + radius;
var y = Math.sin((90 - deg) * (180 / Math.PI)) * radius + radius;
console.log(x + " " + y);
element.style.position = "absolute";
element.style.left = x + "px";
element.style.top = y + "px";
element.style.transform = "rotate(" + deg + "deg)";
clock.appendChild(element);
}
}
function addClass(element, name) {
var arr;
arr = element.className.split(" ");
if (arr.indexOf(name) == -1) {
element.className += " " + name;
}
}
* {
margin: 0;
padding: 0;
border: 0;
}
body {
background-color: #000;
}
#clock {
height: 500px;
width: 500px;
background-color: #DDDDDD;
border-radius: 100%;
position: absolute;
}
.h {
width: 10px;
height: 70px;
background-color: red
}
.m {
width: 5px;
height: 80px;
background-color: blue
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Page Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" media="screen" href="main.css" />
<script src="main.js"></script>
</head>
<body>
<div id="clock">
</div>
</body>
</html>
Here is a clock example made by Eric Brewer on CodePen.
I have compiled SCSS and Pug keeping only the necessary parts of the code to make the clock work. This version doesn't require any JavaScript to run.
However, I have added some JavaScript code to make it start from a particular position. This can be achieved using the class Date to get the current date and setting the animation-delay CSS property with the property animationDelay for each clock arms.
Here is the working code:
let setTime = function(date) {
const delay = [
date.getHours() * 3600 + date.getMinutes() * 60 + date.getSeconds(),
date.getMinutes() * 60 + date.getSeconds(),
date.getSeconds()
];
[...document.querySelectorAll('.hand')].forEach((e, i) => e.style.animationDelay = `-${delay[i]}s`);
}
setTime(new Date())
body {
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
/* Main style for the clock */
.face {
position: relative;
display: flex;
justify-content: center;
align-items: flex-start;
width: 400px;
height: 400px;
background: #eee;
border-radius: 50%;
padding: 20px;
border: 20px solid #d9d9d9;
}
.face:after {
display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
content: "";
border-radius: 50%;
z-index: 3;
}
/* Numbers: styling and positioning */
.numbers {
position: relative;
}
.number {
position: absolute;
height: 200px;
transform-origin: 0 100%;
font-size: 28px;
}
.number:nth-child(1) {
transform: rotate(25deg);
}
.number:nth-child(1) span {
display: block;
transform: rotate(-25deg);
}
.number:nth-child(2) {
transform: rotate(55deg);
}
.number:nth-child(2) span {
display: block;
transform: rotate(-55deg);
}
.number:nth-child(3) {
transform: rotate(85deg);
}
.number:nth-child(3) span {
display: block;
transform: rotate(-85deg);
}
.number:nth-child(4) {
transform: rotate(115deg);
}
.number:nth-child(4) span {
display: block;
transform: rotate(-115deg);
}
.number:nth-child(5) {
transform: rotate(145deg);
}
.number:nth-child(5) span {
display: block;
transform: rotate(-145deg);
}
.number:nth-child(6) {
transform: rotate(178deg);
}
.number:nth-child(6) span {
display: block;
transform: rotate(-175deg);
}
.number:nth-child(7) {
transform: rotate(205deg);
}
.number:nth-child(7) span {
display: block;
transform: rotate(-205deg);
}
.number:nth-child(8) {
transform: rotate(235deg);
}
.number:nth-child(8) span {
display: block;
transform: rotate(-235deg);
}
.number:nth-child(9) {
transform: rotate(265deg);
}
.number:nth-child(9) span {
display: block;
transform: rotate(-265deg);
}
.number:nth-child(10) {
transform: rotate(295deg);
}
.number:nth-child(10) span {
display: block;
transform: rotate(-295deg);
}
.number:nth-child(11) {
transform: rotate(325deg);
}
.number:nth-child(11) span {
display: block;
transform: rotate(-325deg);
}
.number:nth-child(12) {
transform: rotate(355deg);
}
.number:nth-child(12) span {
display: block;
transform: rotate(-355deg);
}
/* Clock hands styling */
.hands {
position: absolute;
top: 50%;
left: 50%;
}
.hand {
position: absolute;
top: 50%;
left: 50%;
height: 120px;
width: 10px;
content: "";
background: black;
transform: translate(-50%, -100%);
border-radius: 0 0 20px 20px;
transform-origin: 50% 100%;
z-index: 4;
animation: count 3600s linear infinite;
}
.hand:before {
display: block;
position: absolute;
top: -50px;
width: 0;
height: 0;
border: 10px solid transparent;
border-width: 10px 5px 41px;
border-bottom-color: black;
content: "";
}
.hand.hand-hour {
height: 70px;
transform: translate(-50%, -100%) rotate(30deg);
animation: count 43200s linear infinite;
}
.hand.hand-second {
height: 130px;
width: 8px;
transform: translate(-50%, -100%) rotate(60deg);
z-index: 3;
background: red;
animation: count 60s linear infinite;
}
.hand.hand-second .body {
display: block;
position: relative;
top: 0;
left: 0;
width: 100%;
height: 100%;
content: "";
background: red;
z-index: 4;
}
.hand.hand-second:before {
border-width: 10px 4px 41px;
border-bottom-color: red;
z-index: -1;
}
/* animation of the clock hands */
#keyframes count {
0%,
100% {
transform: translate(-50%, -100%);
}
25% {
transform: translate(-50%, -100%) rotate(90deg);
}
50% {
transform: translate(-50%, -100%) rotate(180deg);
}
75% {
transform: translate(-50%, -100%) rotate(270deg);
}
}
<div class="watch">
<div class="face">
<div class="numbers">
<div class="number number-1"><span>1</span></div>
<div class="number number-2"><span>2</span></div>
<div class="number number-3"><span>3</span></div>
<div class="number number-4"><span>4</span></div>
<div class="number number-5"><span>5</span></div>
<div class="number number-6"><span>6</span></div>
<div class="number number-7"><span>7</span></div>
<div class="number number-8"><span>8</span></div>
<div class="number number-9"><span>9</span></div>
<div class="number number-10"><span>10</span></div>
<div class="number number-11"><span>11</span></div>
<div class="number number-12"><span>12</span></div>
</div>
<div class="hands">
<div class="hand hand-hour"></div>
<div class="hand hand-minute"></div>
<div class="hand hand-second">
<div class="body"></div>
</div>
</div>
</div>
</div>
Simply set the current date in date, the JavaScript code will loop through the clock's arms and delay each animation. CSS animation will allow the clock to run continuously after page has been loaded.
This method is a lot more efficient than using a JavaScript function to compute the positions and move clock hands. CSS animations are way more powerful here.
EDIT :
When you're programming a piece of code you should always start with a piece of paper and define what you want, how you will achieve it before starting typing. You have to have a plan before typing, otherwise, it will simply not work.
So as you told me you only want to position the number ticks (the original question wasn't that clear...). It's easier to have all ticks as black rectangles positioned in the center, set their height and width. So we have:
Then use the transform property to rotate each tick to the right angle: 0°, 30°, 60°, 90°, ..., 300°, 330° and 360°. Use rotate(x deg).
Lastly here's the trick to the set the ticks' size correctly:
use a gradient to hide the part of the tick closer to the center so we only show the tip of each tick:
background: linear-gradient(
to top,
#eee 0%,
#eee 80%,
black 80%,
black 100%
);
In the end you should have:
Combining this with the previous code to make the clock turn you get:
let drawTicks = function() {
for (let i = 1; i < 13; i++) {
let el = document.createElement('div');
el.setAttribute('class', `number number${i}`);
el.style.transform = `rotate(${i*30}deg)`;
document.querySelector('.numbers').appendChild(el);
}
}; drawTicks()
let setTime = function(date) {
const delay = [
date.getHours() * 3600 + date.getMinutes() * 60 + date.getSeconds(),
date.getMinutes() * 60 + date.getSeconds(),
date.getSeconds()
];
[...document.querySelectorAll('.hand')].forEach((e, i) => e.style.animationDelay = `-${delay[i]}s`);
}; setTime(new Date())
body {
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
/* Main style for the clock */
.face {
position: relative;
display: flex;
justify-content: center;
align-items: flex-start;
width: 400px;
height: 400px;
background: #eee;
border-radius: 50%;
padding: 20px;
border: 20px solid #d9d9d9;
}
.face:after {
display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
content: "";
border-radius: 50%;
z-index: 3;
}
/* Numbers: styling and positioning */
.numbers {
position: relative;
}
.number {
width: 5px;
background: linear-gradient( to top, #eee 0%, #eee 80%, black 80%, black 100%);
position: absolute;
height: 200px;
transform-origin: 0 100%;
font-size: 28px;
}
/* Clock hands styling */
.hands {
position: absolute;
top: 50%;
left: 50%;
}
.hand {
position: absolute;
top: 50%;
left: 50%;
height: 120px;
width: 10px;
content: "";
background: black;
transform: translate(-50%, -100%);
border-radius: 0 0 20px 20px;
transform-origin: 50% 100%;
z-index: 4;
animation: count 3600s linear infinite;
}
.hand:before {
display: block;
position: absolute;
top: -50px;
width: 0;
height: 0;
border: 10px solid transparent;
border-width: 10px 5px 41px;
border-bottom-color: black;
content: "";
}
.hand.hand-hour {
height: 70px;
transform: translate(-50%, -100%) rotate(30deg);
animation: count 43200s linear infinite;
}
.hand.hand-second {
height: 130px;
width: 8px;
transform: translate(-50%, -100%) rotate(60deg);
z-index: 3;
background: red;
animation: count 60s linear infinite;
}
.hand.hand-second:before {
border-width: 10px 4px 41px;
border-bottom-color: red;
z-index: -1;
}
/* animation of the clock hands */
#keyframes count {
0%,
100% {
transform: translate(-50%, -100%);
}
25% {
transform: translate(-50%, -100%) rotate(90deg);
}
50% {
transform: translate(-50%, -100%) rotate(180deg);
}
75% {
transform: translate(-50%, -100%) rotate(270deg);
}
}
<div class="watch">
<div class="face">
<div class="numbers"></div>
<div class="hands">
<div class="hand hand-hour"></div>
<div class="hand hand-minute"></div>
<div class="hand hand-second">
</div>
</div>
</div>
</div>
Related
I need help!
Here is my codepen
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Bebas+Neue&display=swap" rel="stylesheet">
<link href='https://fonts.googleapis.com/css?family=Montserrat' rel='stylesheet' type='text/css'>
<div class="container">
<h1>Custom Cursor</h1>
<div class="box">
</div>
</div>
</div>
<div class="btn">
<span style="--i:1">J</span>
<span style="--i:2">o</span>
<span style="--i:3">u</span>
<span style="--i:4">e</span>
<span style="--i:5">r</span>
<span style="--i:6"> </span>
<span style="--i:7">l</span>
<span style="--i:8">a</span>
<span style="--i:9"> </span>
<span style="--i:10">v</span>
<span style="--i:11">i</span>
<span style="--i:12">d</span>
<span style="--i:13">é</span>
<span style="--i:14">o</span>
<span style="--i:15"> </span>
<span style="--i:16">-</span>
<span style="--i:17"> </span>
<span style="--i:18">J</span>
<span style="--i:19">o</span>
<span style="--i:20">u</span>
<span style="--i:21">e</span>
<span style="--i:22">r</span>
<span style="--i:23"> </span>
<span style="--i:24">l</span>
<span style="--i:25">a</span>
<span style="--i:26"> </span>
<span style="--i:27">v</span>
<span style="--i:28">i</span>
<span style="--i:29">d</span>
<span style="--i:30">é</span>
<span style="--i:31">o</span>
<span style="--i:32"> </span>
<span style="--i:33">-</span>
<span style="--i:34"> </span>
<span style="--i:35">J</span>
<span style="--i:36">o</span>
<span style="--i:37">u</span>
<span style="--i:38">e</span>
<span style="--i:39">r</span>
<span style="--i:40"> </span>
<span style="--i:41">l</span>
<span style="--i:42">a</span>
<span style="--i:43"> </span>
<span style="--i:44">v</span>
<span style="--i:45">i</span>
<span style="--i:46">d</span>
<span style="--i:47">é</span>
<span style="--i:48">o</span>
<span style="--i:49"> </span>
<span style="--i:50">-</span>
<span style="--i:51"> </span>
</div>
<div class="triangle"></div>
<div class="circle"></div>
body {
background: red;
height: 100vh;
font-family: Bebas neue;
display: flex;
justify-content: center;
align-items: center;
}
h1 {
font-family: montserrat;
font-size: 40px;
}
.container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: white;
flex-direction: column;
}
.box {
width: 800px;
height: 450px;
background-color: pink;
border: 2px solid red;
border-radius: 10px;
display: flex;
justify-content: center;
align-items: center;
}
.box:hover {
cursor: none;
}
.block {
display: block !important;
opacity: 1 !important;
}
.btn {
width: 138px;
height: 138px;
font-weight: bold;
font-size: 30px;
position: absolute;
animation: loading 6s linear infinite;
opacity: 0;
}
.triangle {
height: 0;
width: 0;
border-top: 40px solid transparent;
border-bottom: 40px solid transparent;
border-left: 60px solid white;
transform: translateX(-25%) translateY(-50%);
display: none;
position: fixed;
pointer-events: none;
left: 0;
top: 0;
}
.circle {
border:1px solid white;
width: 138px;
height: 138px;
border-radius: 50%;
/*transform: translateX(-142.5%) translateY(-0.5%);*/
transform: translateX(-45%) translateY(-50%);
display: none;
position: fixed;
pointer-events: none;
left: 0;
top: 0;
}
.btn span {
position: absolute;
left: 50%;
transform-origin: 0 120px ;
transform: translateX(0%) translateY(0%) rotateZ(calc(var(--i) * 7.05deg)); /* 360 / nbr de lettre */
color: white;
position: fixed;
pointer-events: none;
top: 50px;
}
#keyframes loading {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(-360deg);
}
}
var box = document.querySelector(".box");
var btn = document.querySelector(".btn");
var circle = document.querySelector(".circle");
var triangle = document.querySelector(".triangle");
document.addEventListener("mousemove", function (e) {
var x = e.clientX;
var y = e.clientY;
//triangle.style.transform = `translate3d(calc(${e.clientX}px - 50%), calc(${e.clientY}px - 50%), 0)`;
triangle.style.left = x + "px";
triangle.style.top = y + "px";
});
document.addEventListener("mousemove", function (e) {
var x = e.clientX;
var y = e.clientY;
// circle.style.transform = `translate3d(calc(${e.clientX}px - 50%), calc(${e.clientY}px - 50%), 0)`;
circle.style.left = x + "px";
circle.style.top = y + "px";
});
document.addEventListener("mousemove", function (e) {
var x = e.clientX;
var y = e.clientY;
// btn.style.transform = `translate3d(calc(${e.clientX}px - 50%), calc(${e.clientY}px - 50%), 0)`;
btn.style.left = x + "px";
btn.style.top = y + "px";
});
box.addEventListener("mouseenter", () => {
triangle.classList.add("block");
circle.classList.add("block");
btn.classList.add("block");
});
box.addEventListener("mouseleave", () => {
triangle.classList.remove("block");
circle.classList.remove("block");
btn.classList.remove("block");
});
I want to be able to hide my cursor when I hover over a zone
and when I am on this zone (in the codepen this zone is the div .box)
I want to make a custom cursor appear.
The complexity comes from the fact that I want my triangle, circle and rounded text elements to be aligned at their centre. I also want the text to rotate on itself.
I think I'm not far off but the text turns with an offset
Can you help me?
thank you
https://codepen.io/jipe974/pen/abjxoNy
I find the solution thanks all
var box = document.querySelector(".box");
var innerbox = document.querySelector(".innerbox");
var box2 = document.querySelector(".box2");
var cursor = document.querySelector(".cursor");
var cursorinner = document.querySelector(".cursor2");
var circle = document.querySelector("#circle");
var triangle = document.querySelector("#triangle");
document.addEventListener("mousemove", function (e) {
var x = e.clientX;
var y = e.clientY;
cursor.style.transform = `translate3d(calc(${e.clientX}px - 50%), calc(${e.clientY}px - 50%), 0)`;
cursorinner.style.left = x + "px";
cursorinner.style.top = y + "px";
circle.style.left = x + "px";
circle.style.top = y + "px";
triangle.style.left = x + "px";
triangle.style.top = y + "px";
});
document.addEventListener("mousedown", function () {
cursorinner.classList.add("cursorinnerhover");
circle.classList.add("click");
triangle.classList.add("click");
});
document.addEventListener("mouseup", function () {
cursorinner.classList.remove("cursorinnerhover");
circle.classList.remove("click");
triangle.classList.remove("click");
});
box.addEventListener("mouseenter", () => {
cursor.classList.add("block");
cursorinner.classList.add("block");
});
box.addEventListener("mouseleave", () => {
cursor.classList.remove("block");
cursorinner.classList.remove("block");
});
innerbox.addEventListener("mouseover", () => {
cursor.classList.add("hover");
});
innerbox.addEventListener("mouseleave", () => {
cursor.classList.remove("hover");
});
box2.addEventListener("mouseenter", () => {
circle.classList.add("opacity");
triangle.classList.add("opacity");
});
box2.addEventListener("mouseleave", () => {
circle.classList.remove("opacity");
triangle.classList.remove("opacity");
});
#import url("https://fonts.googleapis.com/css?family=Montserrat&display=swap");
body {
overflow-x: hidden;
background:red;
}
h1 {
font-family: montserrat;
font-size: 40px;
}
.container {
display: flex;
justify-content: center;
align-items: center;
height: 1000px;
flex-direction: column;
}
.innerbox {
width: 500px;
height: 350px;
background-color: blue;
border-radius: 10px;
}
.innerbox:hover {
background-color: white;
}
.box {
width: 800px;
height: 450px;
background-color: pink;
display: flex;
justify-content: center;
align-items: center;
}
.box:hover, .box2:hover {
cursor: none;
}
.box2 {
width: 800px;
height: 450px;
background-color: aqua;
}
.cursor {
width: 50px;
height: 50px;
border-radius: 100%;
border: 1px solid black;
transition: all 200ms ease-out;
position: fixed;
pointer-events: none;
left: 0;
top: 0;
transform: translate(calc(-50% + 15px), -50%);
display: none;
}
.cursor2 {
width: 20px;
height: 20px;
border-radius: 100%;
background-color: black;
opacity: 0.3;
position: fixed;
transform: translate(-50%, -50%);
pointer-events: none;
transition: width 0.3s, height 0.3s, opacity 0.3s;
display: none;
}
.hover {
background-color: red;
opacity: 0.5;
}
.cursorinnerhover {
width: 50px;
height: 50px;
opacity: 0.5;
}
.block {
display: block !important;
}
.opacity {
opacity: 1 !important;
}
#circle {
transform: translate(-49.9%, -4.5%);
position: fixed;
width: 100%;
padding-bottom: 100%;
overflow: hidden;
opacity: 0;
pointer-events: none;
}
#triangle {
transform: translate(-1%, -0.7%);
position: fixed;
width: 100%;
padding-bottom: 100%;
overflow: hidden;
opacity: 0;
pointer-events: none;
fill: white;
}
#circle text {
font-family: "Helvetica Neue", Arial;
font-size: 24px;
font-weight: bold;
}
#circle circle {
stroke: white;
fill: none;
}
#circle svg {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 240px;
-webkit-animation-name: rotate;
-moz-animation-name: rotate;
-ms-animation-name: rotate;
-o-animation-name: rotate;
animation-name: rotate;
-webkit-animation-duration: 5s;
-moz-animation-duration: 5s;
-ms-animation-duration: 5s;
-o-animation-duration: 5s;
animation-duration: 5s;
-webkit-animation-iteration-count: infinite;
-moz-animation-iteration-count: infinite;
-ms-animation-iteration-count: infinite;
-o-animation-iteration-count: infinite;
animation-iteration-count: infinite;
-webkit-animation-timing-function: linear;
-moz-animation-timing-function: linear;
-ms-animation-timing-function: linear;
-o-animation-timing-function: linear;
animation-timing-function: linear;
}
#-webkit-keyframes rotate {
from {
-webkit-transform: rotate(360deg);
}
to {
-webkit-transform: rotate(0);
}
}
#-moz-keyframes rotate {
from {
-moz-transform: rotate(360deg);
}
to {
-moz-transform: rotate(0);
}
}
#-ms-keyframes rotate {
from {
-ms-transform: rotate(360deg);
}
to {
-ms-transform: rotate(0);
}
}
#-o-keyframes rotate {
from {
-o-transform: rotate(360deg);
}
to {
-o-transform: rotate(0);
}
}
#keyframes rotate {
from {
transform: rotate(360deg);
}
to {
transform: rotate(0);
}
}
.click {
fill: #E1E1E1!important;
stroke: #E1E1E1!important;
stroke-width:2;
}
<div class="container">
<h1>Custom Cursor</h1>
<div class="box">
<div class="innerbox">
</div>
</div>
<div>
<video class="box2" controls loop id="video-background" muted>
<source src="https://media-us-westslateappcom.s3.us-west-1.amazonaws.com/madcowfilms/production/clips/514ebae1-ebbb-4477-addd-d52a30cd28c1-1280x720.2500.webm" type="video/webm">
</div>
</div>
<div class="cursor"></div>
<div class="cursor2"></div>
<div id="circle">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="300px" height="300px" viewBox="0 0 300 300" enable-background="new 0 0 300 300" xml:space="preserve">
<defs>
<path id="circlePath" d=" M 150, 150 m -60, 0 a 60,60 0 0,1 120,0 a 60,60 0 0,1 -120,0 " />
</defs>
<circle cx="150" cy="150" r="50" fill="none" />
<g>
<use xlink:href="#circlePath" fill="none" />
<text fill="#fff">
<textPath xlink:href="#circlePath">Jouer la vidéo - Jouer la vidéo -
<textPath>
</text>
</g>
</svg>
</div>
<div id="triangle">
<svg>
<polygon points="45,22.5 22.5,0 22.5,45"/>
</svg>
</div>
but according to the screen I have the triangle that shifts
look at the solution you can maybe apply.
To start you needs to create parent div .cursor, which contains all your elements like .circle, .btn and .triangle.
<html lang="en">
<body>
<div class="container">
<h1>Custom Cursor</h1>
<div class="box"></div>
</div>
<div class="cursor">
<div class="circle"></div>
<div class="btn">
<!-- Your spans -->
</div>
<div class="triangle"></div>
</div>
</body>
</html>
This new div .cursor should contain new properties :
/* Parent box, contain triangle, btn and circle */
.cursor {
position: absolute;
display: flex;
/* Center triangle in the middle */
align-items: center;
justify-content: center;
pointer-events: none;
opacity: 0;
}
Then you should update properties of childs css, because they will take opacity and display from the parent.
/* Remove opacity and position absolute*/
.btn {
width: 138px;
height: 138px;
font-weight: bold;
font-size: 30px;
animation: loading 6s linear infinite;
}
/*
Remove height, left, top, display (block by parent)
change position to absolute
*/
.triangle {
border-top: 40px solid transparent;
border-bottom: 40px solid transparent;
border-left: 60px solid white;
pointer-events: none;
position: absolute;
}
/*
Remove left, top, display (block by parent)
change position to absolute
*/
.circle {
border: 1px solid white;
width: 138px;
height: 138px;
border-radius: 50%;
pointer-events: none;
outline: 2px solid rgb(0, 255, 191);
position: absolute;
}
Like all elements are in the div .cursor, now we will only act on this one.
var box = document.querySelector(".box");
// Cursor box contain all child element, btn, circle, triangle
var cursor = document.querySelector(".cursor");
const halfSizeCircle = 138 / 2; // 69
box.addEventListener("mousemove", function (e) {
// Get coordinate middle of the mouse inside div .box
var [x, y] = [e.clientY - halfSizeCircle, e.clientX - halfSizeCircle];
cursor.style.top = x + "px";
cursor.style.left = y + "px";
});
// Remove class .block
box.addEventListener("mouseleave", () => cursor.classList.remove("block"));
// Add class .block
box.addEventListener("mouseenter", () => cursor.classList.add("block"));
Hope this solution will help you 🧙♂️.
import {css, html, LitElement} from 'lit';
class AnalogClock extends LitElement {
static get properties() {
return {
time: {type: Date},
interval: {type: Object}
};
}
static get styles() {
return css`
.clock {
width: 30rem;
height: 30rem;
border: 7px solid #282828;
box-shadow: -4px -4px 10px rgba(67,67,67,0.5),
inset 4px 4px 10px rgba(0,0,0,0.5),
inset -4px -4px 10px rgba(67,67,67,0.5),
4px 4px 10px rgba(0,0,0,0.3);
border-radius: 50%;
margin: 50px auto;
position: relative;
padding: 2rem;
}
.outer-clock-face {
position: relative;
width: 100%;
height: 100%;
border-radius: 100%;
background: #282828;
overflow: hidden;
}
.outer-clock-face::after {
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
transform: rotate(90deg)
}
.outer-clock-face::before,
.outer-clock-face::after,
.outer-clock-face .marking{
content: '';
position: absolute;
width: 5px;
height: 100%;
background: #1df52f;
z-index: 0;
left: 49%;
}
.outer-clock-face .marking {
background: #bdbdcb;
width: 3px;
}
.outer-clock-face .marking.marking-one {
-webkit-transform: rotate(30deg);
-moz-transform: rotate(30deg);
transform: rotate(30deg)
}
.outer-clock-face .marking.marking-two {
-webkit-transform: rotate(60deg);
-moz-transform: rotate(60deg);
transform: rotate(60deg)
}
.outer-clock-face .marking.marking-three {
-webkit-transform: rotate(120deg);
-moz-transform: rotate(120deg);
transform: rotate(120deg)
}
.outer-clock-face .marking.marking-four {
-webkit-transform: rotate(150deg);
-moz-transform: rotate(150deg);
transform: rotate(150deg)
}
.inner-clock-face {
position: absolute;
top: 10%;
left: 10%;
width: 80%;
height: 80%;
background: #282828;
-webkit-border-radius: 100%;
-moz-border-radius: 100%;
border-radius: 100%;
z-index: 1;
}
.inner-clock-face::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 16px;
height: 16px;
border-radius: 18px;
margin-left: -9px;
margin-top: -6px;
background: #4d4b63;
z-index: 11;
}
.hand {
width: 50%;
right: 50%;
height: 6px;
background: #61afff;
position: absolute;
top: 50%;
border-radius: 6px;
transform-origin: 100%;
transform: rotate(90deg);
transition-timing-function: cubic-bezier(0.1, 2.7, 0.58, 1);
}
.hand.hour-hand {
width: 30%;
z-index: 3;
}
.hand.min-hand {
height: 3px;
z-index: 10;
width: 40%;
}
.hand.second-hand {
background: #ee791a;
width: 45%;
height: 2px;
}
`;
}
render() {
return html`
<div class="clock">
<div class="outer-clock-face">
<div class="marking marking-one"></div>
<div class="marking marking-two"></div>
<div class="marking marking-three"></div>
<div class="marking marking-four"></div>
<div class="inner-clock-face">
<div class="hand hour-hand"></div>
<div class="hand min-hand"></div>
<div class="hand second-hand"></div>
</div>
</div>
</div>
`;
}
setDate(time) {
const secondHand = this.shadowRoot.querySelector('.second-hand');
const minsHand = this.shadowRoot.querySelector('.min-hand');
const hourHand = this.shadowRoot.querySelector('.hour-hand');
const now = time;
const seconds = now.getSeconds();
const secondsDegrees = ((seconds / 60) * 360) + 90;
secondHand.style.transform = `rotate(${secondsDegrees}deg)`;
const mins = now.getMinutes();
const minsDegrees = ((mins / 60) * 360) + ((seconds / 60) * 6) + 90;
minsHand.style.transform = `rotate(${minsDegrees}deg)`;
const hour = now.getHours();
const hourDegrees = ((hour / 12) * 360) + ((mins / 60) * 30) + 90;
hourHand.style.transform = `rotate(${hourDegrees}deg)`;
}
constructor() {
super();
this.time = new Date();
this.updateComplete.then(() => {
this.setDate(this.time);
this.interval = setInterval(() => {
this.time = new Date(this.time.setSeconds(this.time.getSeconds() + 1));
this.setDate(this.time);
}, 1000);
}
);
}
}
window.customElements.define('analog-clock', AnalogClock);
My component class
The view where I bring the clock in
The result of bringing the clock into the application, which has removed all my previous styles
The clock is a JavaScript file which I have very little experience using, I am bringing the clock into my Vaadin application using the spring #JsModule annotation and it appears to be over riding all my current CSS styling. If anyone can shed some light on this it would be much appreciated.
I am trying to implement an Analog clock into my Vaadin 14 Spring Boot project.
I have found many Analog clocks online written in JavaScript/HTML/CSS and I have tried to import these files into Vaadin using the #HtmlImport, #JsModule #JavaScript and #Tag annotations.
I have been successful at getting the clock displayed but without any moving parts. I will attach the HTML file I have been using.
Here is the link to the source:
https://www.foolishdeveloper.com/2021/07/simple-analog-clock-html-css-javascript.html
What is the proper way of getting this clock implemented?
Any advice will be much appreciated.
import {html, PolymerElement} from '#polymer/polymer/polymer-element.js';
class AnalogClockContainer extends PolymerElement {
static get template() {
return html`
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<style>
.clock {
width: 30rem;
height: 30rem;
border: 7px solid #282828;
box-shadow: -4px -4px 10px rgba(67, 67, 67, 0.5),
inset 4px 4px 10px rgba(0, 0, 0, 0.5),
inset -4px -4px 10px rgba(67, 67, 67, 0.5),
4px 4px 10px rgba(0, 0, 0, 0.3);
border-radius: 50%;
margin: 50px auto;
position: relative;
padding: 2rem;
}
.outer-clock-face {
position: relative;
width: 100%;
height: 100%;
border-radius: 100%;
background: #282828;
overflow: hidden;
}
.outer-clock-face::after {
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
transform: rotate(90deg)
}
.outer-clock-face::before,
.outer-clock-face::after,
.outer-clock-face .marking {
content: '';
position: absolute;
width: 5px;
height: 100%;
background: #1df52f;
z-index: 0;
left: 49%;
}
.outer-clock-face .marking {
background: #bdbdcb;
width: 3px;
}
.outer-clock-face .marking.marking-one {
-webkit-transform: rotate(30deg);
-moz-transform: rotate(30deg);
transform: rotate(30deg)
}
.outer-clock-face .marking.marking-two {
-webkit-transform: rotate(60deg);
-moz-transform: rotate(60deg);
transform: rotate(60deg)
}
.outer-clock-face .marking.marking-three {
-webkit-transform: rotate(120deg);
-moz-transform: rotate(120deg);
transform: rotate(120deg)
}
.outer-clock-face .marking.marking-four {
-webkit-transform: rotate(150deg);
-moz-transform: rotate(150deg);
transform: rotate(150deg)
}
.inner-clock-face {
position: absolute;
top: 10%;
left: 10%;
width: 80%;
height: 80%;
background: #282828;
-webkit-border-radius: 100%;
-moz-border-radius: 100%;
border-radius: 100%;
z-index: 1;
}
.inner-clock-face::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 16px;
height: 16px;
border-radius: 18px;
margin-left: -9px;
margin-top: -6px;
background: #4d4b63;
z-index: 11;
}
.hand {
width: 50%;
right: 50%;
height: 6px;
background: #61afff;
position: absolute;
top: 50%;
border-radius: 6px;
transform-origin: 100%;
transform: rotate(90deg);
transition-timing-function: cubic-bezier(0.1, 2.7, 0.58, 1);
}
.hand.hour-hand {
width: 30%;
z-index: 3;
}
.hand.min-hand {
height: 3px;
z-index: 10;
width: 40%;
}
.hand.second-hand {
background: #ee791a;
width: 45%;
height: 2px;
}
</style>
</head>
<body>
<div class="clock">
<div class="outer-clock-face">
<div class="marking marking-one"></div>
<div class="marking marking-two"></div>
<div class="marking marking-three"></div>
<div class="marking marking-four"></div>
<div class="inner-clock-face">
<div class="hand hour-hand"></div>
<div class="hand min-hand"></div>
<div class="hand second-hand"></div>
</div>
</div>
</div>
</body>
</html>
`;
}
}
window.customElements.define('analog-clock-container', AnalogClockContainer);
const secondHand = document.querySelector('.second-hand');
const minsHand = document.querySelector('.min-hand');
const hourHand = document.querySelector('.hour-hand');
function setDate() {
const now = new Date();
const seconds = now.getSeconds();
const secondsDegrees = ((seconds / 60) * 360) + 90;
secondHand.style.transform = `rotate(${secondsDegrees}deg)`;
const mins = now.getMinutes();
const minsDegrees = ((mins / 60) * 360) + ((seconds/60)*6) + 90;
minsHand.style.transform = `rotate(${minsDegrees}deg)`;
const hour = now.getHours();
const hourDegrees = ((hour / 12) * 360) + ((mins/60)*30) + 90;
hourHand.style.transform = `rotate(${hourDegrees}deg)`;
}
setInterval(setDate, 1000);
setDate();
This is my Java class that I am trying to bring the clock into
I am working on a project of mine and was playing around with the idea to make a custom cursor for my webpage.
Unfortunately, it seems that I can't get it to work.
Can someone tell me what I am doing wrong here?
I am using simple HTML, CSS and Javascript.
I think it is the Javascript that's not working, but I have tried to use a debugger but no luck.
<!DOCTYPE html>
<html lang="en">
<head>
<style>
* {
box-sizing: border-box;
cursor: none;
}
body {
background: #000;
color: #fff;
}
a {
color: #fff;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
.custom-cursor {
position: fixed;
top: -18px;
left: -18px;
display: block;
width: 120px;
height: 120px;
pointer-events: none;
will-change: transform;
z-index: 998;
-webkit-transform: matrix(1, 0, 0, 1, -100, -100);
transform: matrix(1, 0, 0, 1, -100, -100);
opacity: 0;
mix-blend-mode: difference;
transition: transform 0.15s cubic-bezier(0, 0.89, 0.49, 0.92),
opacity 0.4s ease;
}
.custom-cursor .cursor {
transform: scale(0.45);
transition: transform 0.5s ease;
will-change: transform;
width: 120px;
height: 120px;
float: left;
border-radius: 100%;
margin-top: -40px;
margin-left: -40px;
background: #fff;
}
.custom-cursor.custom-cursor-active .cursor {
-webkit-transform: scale(1);
transform: scale(1);
opacity: 1;
}
.custom-cursor.custom-cursor-active-img {
z-index: 1010;
}
.custom-cursor.custom-cursor-active-img .cursor {
-webkit-transform: scale(1);
transform: scale(1);
opacity: 1;
background: #ff0;
}
body:hover .custom-cursor {
opacity: 1;
}
#media screen and (max-width: 1200px) {
.custom-cursor {
display: none !important;
}
}
.center {
padding: 30vh;
text-align: center;
width: 100%;
position: relative;
z-index: 9999;
}
.content {
padding: 1em;
font-family: sans-serif;
font-size: 3em;
background: #000;
min-height: 100vh;
}
.content::before {
position: fixed;
background: #ff0;
mix-blend-mode: multiply;
content: "";
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 999;
pointer-events: none;
}
.img-wrapper {
max-width: 450px;
padding: 100px 0;
}
.img {
position: relative;
z-index: 1000;
}
</style>
</head>
<body>
<div class="content">
<div class="custom-cursor" data-custom-cursor>
<div class="cursor"></div>
</div>
<h1>hello world</h1>
link 0 / link 1 /
link 2 / link 3 /
link 4 / link 5 /
link 6 / link 7 /
link 8 .
</div>
<script>
const cursor = document.querySelector(".cursor");
document.addEventListener("mousemove", (e) => {
cursor.setAttribute(
"style",
"top: " + (e.pageY - 10) + "px; left: " + (e.pageX - 10) + "px;"
);
});
var $c = $("[data-custom-cursor]");
var $h = $("a, button");
var $i = $("img");
$(window).on("mousemove", function (e) {
x = e.clientX;
y = e.clientY;
console.log(x, y);
$c.css("transform", "matrix(1, 0, 0, 1, " + x + "," + y + ")");
});
$h.on("mouseenter", function (e) {
$c.addClass("custom-cursor-active");
});
$h.on("mouseleave", function (e) {
$c.removeClass("custom-cursor-active");
});
$i.on("mouseenter", function (e) {
$c.addClass("custom-cursor-active-img");
});
$i.on("mouseleave", function (e) {
$c.removeClass("custom-cursor-active-img");
});
//# sourceURL=pen.js
</script>
</body>
</html>
The code seems to work (at least, it does things though I don't know if they are the right things) as long as jquery is also loaded.
<html lang="en"><head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<style>
* {
box-sizing: border-box;
cursor: none;
}
body {
background: #000;
color: #fff;
}
a {
color: #fff;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
.custom-cursor {
position: fixed;
top: -18px;
left: -18px;
display: block;
width: 120px;
height: 120px;
pointer-events: none;
will-change: transform;
z-index: 998;
-webkit-transform: matrix(1, 0, 0, 1, -100, -100);
transform: matrix(1, 0, 0, 1, -100, -100);
opacity: 0;
mix-blend-mode: difference;
transition: transform 0.15s cubic-bezier(0, 0.89, 0.49, 0.92),
opacity 0.4s ease;
}
.custom-cursor .cursor {
transform: scale(0.45);
transition: transform 0.5s ease;
will-change: transform;
width: 120px;
height: 120px;
float: left;
border-radius: 100%;
margin-top: -40px;
margin-left: -40px;
background: #fff;
}
.custom-cursor.custom-cursor-active .cursor {
-webkit-transform: scale(1);
transform: scale(1);
opacity: 1;
}
.custom-cursor.custom-cursor-active-img {
z-index: 1010;
}
.custom-cursor.custom-cursor-active-img .cursor {
-webkit-transform: scale(1);
transform: scale(1);
opacity: 1;
background: #ff0;
}
body:hover .custom-cursor {
opacity: 1;
}
#media screen and (max-width: 1200px) {
.custom-cursor {
display: none !important;
}
}
.center {
padding: 30vh;
text-align: center;
width: 100%;
position: relative;
z-index: 9999;
}
.content {
padding: 1em;
font-family: sans-serif;
font-size: 3em;
background: #000;
min-height: 100vh;
}
.content::before {
position: fixed;
background: #ff0;
mix-blend-mode: multiply;
content: "";
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 999;
pointer-events: none;
}
.img-wrapper {
max-width: 450px;
padding: 100px 0;
}
.img {
position: relative;
z-index: 1000;
}
</style>
</head>
<body>
<div class="content">
<div class="custom-cursor" data-custom-cursor="" style="transform: matrix(1, 0, 0, 1, 1128, 590);">
<div class="cursor" style="top: 596px; left: 1118px;"></div>
</div>
<h1>hello world</h1>
link 0 / link 1 /
link 2 / link 3 /
link 4 / link 5 /
link 6 / link 7 /
link 8 .
</div>
<script>
const cursor = document.querySelector(".cursor");
document.addEventListener("mousemove", (e) => {
cursor.setAttribute(
"style",
"top: " + (e.pageY - 10) + "px; left: " + (e.pageX - 10) + "px;"
);
});
var $c = $("[data-custom-cursor]");
var $h = $("a, button");
var $i = $("img");
$(window).on("mousemove", function (e) {
x = e.clientX;
y = e.clientY;
console.log(x, y);
$c.css("transform", "matrix(1, 0, 0, 1, " + x + "," + y + ")");
});
$h.on("mouseenter", function (e) {
$c.addClass("custom-cursor-active");
});
$h.on("mouseleave", function (e) {
$c.removeClass("custom-cursor-active");
});
$i.on("mouseenter", function (e) {
$c.addClass("custom-cursor-active-img");
});
$i.on("mouseleave", function (e) {
$c.removeClass("custom-cursor-active-img");
});
//# sourceURL=pen.js
</script>
</body></html>
Note: run the snippet and select full screen mode
I'm currently trying to make a website that displays markers with its own specific text.
When a user clicks on the marker, it displays the text.
I've copied some code online and trying to mess around with it. Unfortunately, I'm not too experience with javascript. I was wondering if anyone would be able to help.
This is what I have so far:
HTML (I don't think there's any problems here):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>MarkerWeb</title>
<link rel="stylesheet" href="style.css">
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
</head>
<body>
<div id="container">
<div id="image-wrapper" data-captions='{"coords": [{"top":250,"left":200,"text":"iMac 1"},{"top":250,"left":540,"text":"iMac 2"}]}'>
<!-- layout.jpg is just a picture of a layout/floorplan -->
<img src="layout.jpg" alt=""/>
</div>
</div>
</body>
<script type="text/javascript" src="script.js"></script>
</html>
Javascript (The part I'm having a hard time with):
var Markers = {
fn: {
addMarkers: function() {
var target = $('#image-wrapper');
var data = target.attr('data-captions');
var captions = $.parseJSON(data);
var coords = captions.coords;
for (var i = 0; i < coords.length; i++) {
var obj = coords[i];
var top = obj.top;
var left = obj.left;
var text = obj.text;
$('<div class="marker"><div class="pin"><span class="popuptext" id="myPopup">' + text + '</span></div><div class="pin-effect"></div></div>').css({
top: top,
left: left
}).appendTo(target);
}
},
//This is the part I'm having trouble with.
showBeaconInfo: function() {
$('body').on('click', '.marker', function() {
var $marker = $(this),
$caption = $('popuptext', $marker);
if ($caption.is(':hidden')) {
$caption.show();
} else {
$caption.toggle("show");
}
});
}
},
init: function() {
this.fn.addMarkers();
this.fn.showBeaconInfo();
}
};
function clickBeacon() {
var popup = document.getElementById("myPopup");
popup.classList.toggle("show");
}
$(function() {
Markers.init();
});
CSS (I don't think there's any problems here):
body {
background: #e6e6e6;
}
#image-wrapper {
width: 800px;
height: 760px;
position: relative;
margin: 2em auto;
background: #f6f6f6;
border: 2px solid #ddd;
}
#image-wrapper img {
display: block;
margin: 25px auto;
}
.map-bg {
background: url(images/map-bg.jpg) no-repeat;
background-position: 0px 0px;
background-size: auto;
width: 100%;
height: 440px; /*adjust to the height of your image*/
position: relative;
}
.marker {
width: 100px;
height: 100px;
position: absolute;
/*top: 130px; /*positions our marker*/
/*left: 200px; /*positions our marker*/
display: block;
}
.pin {
width: 20px;
height: 20px;
position: relative;
top: 38px;
left: 38px;
background: rgba(5, 124, 255, 1);
border: 2px solid #FFF;
border-radius: 50%;
z-index: 1000;
cursor: pointer;
display: inline-block;
}
.pin-effect {
width: 100px;
height: 100px;
position: absolute;
top: 0;
display: block;
background: rgba(5, 124, 255, 0.6);
border-radius: 50%;
opacity: 0;
animation: pulsate 2400ms ease-out infinite;
}
#keyframes pulsate {
0% {
transform: scale(0.1);
opacity: 0;
}
50% {
opacity: 1;
}
100% {
transform: scale(1.2);
opacity: 0;
}
}
/* The actual popup (appears on top) */
.pin .popuptext {
visibility: hidden;
width: 160px;
background-color: #555;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 8px 0;
position: absolute;
z-index: 1;
bottom: 125%;
left: 50%;
margin-left: -80px;
}
/* Popup arrow */
.pin .popuptext::after {
content: "";
position: absolute;
top: 100%;
left: 50%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: #555 transparent transparent transparent;
}
/* Toggle this class when clicking on the popup container (hide and show the popup) */
.pin .show {
visibility: visible;
-webkit-animation: fadeIn 1s;
animation: fadeIn 1s
}
/* Add animation (fade in the popup) */
#-webkit-keyframes fadeIn {
from {opacity: 0;}
to {opacity: 1;}
}
#keyframes fadeIn {
from {opacity: 0;}
to {opacity:1 ;}
}
You need to update your showBeaconInfo function in 2 ways:
1) Fix the selector for $caption to grab the class popuptext by adding a period
2) Using the jquery function toggleClass to add or remove the class "show" on the popuptext, the css is setup to either use visibility: hidden or visibility: visible
showBeaconInfo: function() {
$('body').on('click', '.marker', function() {
var $marker = $(this);
var $caption = $('.popuptext', $marker); //needs period to indicate class
$caption.toggleClass('show'); //adding the class "show" will display the text
});
}
For Example:
var Markers = {
fn: {
addMarkers: function() {
var target = $('#image-wrapper');
var data = target.attr('data-captions');
var captions = $.parseJSON(data);
var coords = captions.coords;
for (var i = 0; i < coords.length; i++) {
var obj = coords[i];
var top = obj.top;
var left = obj.left;
var text = obj.text;
$('<div class="marker"><div class="pin"><span class="popuptext" id="myPopup">' + text + '</span></div><div class="pin-effect"></div></div>').css({
top: top,
left: left
}).appendTo(target);
}
},
//This is the part I'm having trouble with.
showBeaconInfo: function() {
$('body').on('click', '.marker', function() {
var $marker = $(this);
var $caption = $('.popuptext', $marker); //needs period to indicate class
$caption.toggleClass('show'); //adding the class "show" will display the text
});
}
},
init: function() {
this.fn.addMarkers();
this.fn.showBeaconInfo();
}
};
function clickBeacon() {
var popup = document.getElementById("myPopup");
popup.classList.toggle("show");
}
$(function() {
Markers.init();
});
body {
background: #e6e6e6;
}
#image-wrapper {
width: 800px;
height: 760px;
position: relative;
margin: 2em auto;
background: #f6f6f6;
border: 2px solid #ddd;
}
#image-wrapper img {
display: block;
margin: 25px auto;
}
.map-bg {
background: url(images/map-bg.jpg) no-repeat;
background-position: 0px 0px;
background-size: auto;
width: 100%;
height: 440px;
/*adjust to the height of your image*/
position: relative;
}
.marker {
width: 100px;
height: 100px;
position: absolute;
/*top: 130px; /*positions our marker*/
/*left: 200px; /*positions our marker*/
display: block;
}
.pin {
width: 20px;
height: 20px;
position: relative;
top: 38px;
left: 38px;
background: rgba(5, 124, 255, 1);
border: 2px solid #FFF;
border-radius: 50%;
z-index: 1000;
cursor: pointer;
display: inline-block;
}
.pin-effect {
width: 100px;
height: 100px;
position: absolute;
top: 0;
display: block;
background: rgba(5, 124, 255, 0.6);
border-radius: 50%;
opacity: 0;
animation: pulsate 2400ms ease-out infinite;
}
#keyframes pulsate {
0% {
transform: scale(0.1);
opacity: 0;
}
50% {
opacity: 1;
}
100% {
transform: scale(1.2);
opacity: 0;
}
}
/* The actual popup (appears on top) */
.pin .popuptext {
visibility: hidden;
width: 160px;
background-color: #555;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 8px 0;
position: absolute;
z-index: 1;
bottom: 125%;
left: 50%;
margin-left: -80px;
}
/* Popup arrow */
.pin .popuptext::after {
content: "";
position: absolute;
top: 100%;
left: 50%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: #555 transparent transparent transparent;
}
/* Toggle this class when clicking on the popup container (hide and show the popup) */
.pin .show {
visibility: visible;
-webkit-animation: fadeIn 1s;
animation: fadeIn 1s
}
/* Add animation (fade in the popup) */
#-webkit-keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
#keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<div id="image-wrapper" data-captions='{"coords": [{"top":250,"left":200,"text":"iMac 1"},{"top":250,"left":540,"text":"iMac 2"}]}'>
<!-- layout.jpg is just a picture of a layout/floorplan -->
<img src="layout.jpg" alt="" />
</div>
</div>