I try to create a running infotext on an infoscreen. The Text starts running from the right corner of the screen and leaves on the left side. This process repeats without a limit recursively.
Everything seems to work great, but when I remove the alert after debugging, the text don't start running from the right corner but from the left. Also the programm runs only one time.
HTML:
function setStaticData() {
sessionStorage.setItem('headerWidth', document.getElementById('header').scrollWidth);
}
function getStaticData() {
return sessionStorage.getItem('headerWidth');
}
function animation() {
//get element, its width & time param
var header = document.getElementById('header');
var headerWidth = getStaticData();
var headerTime = header.innerHTML.length * 0.3;
var windowWidth = window.innerWidth;
//clean all
header.style.transition = 'none';
header.style.marginLeft = windowWidth + 'px';
alert("baba"); //BAD BOY
//animate text
header.style.transition = 'margin linear ' + headerTime + 's';
header.style.marginLeft = '-' + headerWidth + 'px';
//wait and repeat
var delay = headerTime * 1000 + 1000;
setTimeout(animation, delay);
}
//first call
window.onload = function() {
setStaticData();
animation();
};
html {
width: 100%;
overflow: hidden;
}
body {
height: 100%;
width: 100%;
position: relative;
display: block;
margin: 0;
padding: 0;
top: 50vh;
transform: translateY(-50%);
color: black;
background-color: #bbc8d9;
}
header {
font-family: calibri, arial;
font-weight: 400;
font-size: 100px;
white-space: nowrap;
}
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="style.css">
</head>
<body>
<header id="header">+++ News, More News, Another Thing & something else +++</header>
<script src="functions.js"></script>
</body>
</html>
If I remove the bad boy [alert("baba");] it doesn't work, like I mentioned above.
I going crazy! Can you pls help me?
The problem is that changes to the style of an element are not processed until the Javascript returns to the main event loop and the page is rendered. If you make two assignments to a style, the browser only sees the final result. So when you set marginLeft to the window width and then set it to "-" + headerWidth + "px", only the second change is processed, so that's where the animation starts from.
The alert() causes the page to be rendered while it's waiting for your response (although I think this may be browser-dependent), which is why it works with that.
A simple solution is to put the second assignment in a setTimeout(), so it will be executed asynchronously after returning.
function setStaticData() {
//sessionStorage.setItem('headerWidth', document.getElementById('header').scrollWidth);
}
function getStaticData() {
return document.getElementById('header').scrollWidth; //sessionStorage.getItem('headerWidth');
}
function animation() {
//get element, its width & time param
var header = document.getElementById('header');
var headerWidth = getStaticData();
var headerTime = header.innerHTML.length * 0.3;
var windowWidth = window.innerWidth;
//clean all
header.style.transition = 'none';
header.style.marginLeft = windowWidth + 'px';
//alert("baba"); //BAD BOY
//animate text
setTimeout(function() {
header.style.transition = 'margin linear ' + headerTime + 's';
header.style.marginLeft = '-' + headerWidth + 'px';
}, 0);
//wait and repeat
var delay = headerTime * 1000 + 1000;
setTimeout(animation, delay);
}
//first call
window.onload = function() {
setStaticData();
animation();
};
html {
width: 100%;
overflow: hidden;
}
body {
height: 100%;
width: 100%;
position: relative;
display: block;
margin: 0;
padding: 0;
top: 50vh;
transform: translateY(-50%);
color: black;
background-color: #bbc8d9;
}
header {
font-family: calibri, arial;
font-weight: 400;
font-size: 100px;
white-space: nowrap;
}
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="style.css">
</head>
<body>
<header id="header">+++ News, More News, Another Thing & something else +++</header>
<script src="functions.js"></script>
</body>
</html>
Ok I think i fixed it. Its the timing problem just delay the animate call. 1s
function animation() {
//get element, its width & time param
var header = document.getElementById('header');
var headerWidth = getStaticData();
var headerTime = header.innerHTML.length * 0.3;
var windowWidth = window.innerWidth;
//clean all
header.style.transition = 'none';
header.style.marginLeft = windowWidth+'px';
// delay it for 1000ms
setTimeout(
function(){
//animate text
header.style.transition = 'margin linear '+headerTime+'s';
header.style.marginLeft = '-'+headerWidth+'px';
//wait and repeat
var delay = headerTime * 1000 + 1000;
setTimeout(animation, delay);
}, 1000);
}
Please look at the snippet below. I don't use sessionStorage as it is designed for a different purpose. I don't use setTimeout to wait for the styles to be applied.
I start the animation then restart it on transitionend event.
window.onload = function() {
var header = document.getElementById('header');
animation();
header.addEventListener('transitionend', function() {
header.style.transition = 'none';
header.style.transform = 'translateX(0)';
animation();
});
function animation() {
var t = header.offsetWidth / 70,
tx = header.scrollWidth;
header.style.transition = 'transform ' + t + 's linear';
header.style.transform = 'translateX(-' + tx + 'px)';
}
};
html {
width: 100%;
overflow: hidden;
background-color: #bbc8d9;
}
header {
font: 100px sans-serif;
white-space: nowrap;
padding-left: 100%;
}
<header id="header">+++ News, More News, Another Thing & something else +++</header>
Related
This question already exists:
How to apply a Javascript animation function to multiple elements in for loop? [duplicate]
Closed 10 months ago.
I am trying to apply animation to all of the images created in a for loop without manually doing it, but none of the images created in the for loop are showing any animation, I have tried in multiple ways such as using forEach and a regular for loop paired with querySelectorAll. When I tried to fix my problem with those methods, it either only affected the first image from the for loop or nothing happened at all.
Essentially, what I want is to make it so the 10 images created prior in a for loop can have the same animation as the first image that is being animated across the screen. I also want the other images created to have the same functionality as the first image, when the image is clicked, the click counter should also work similar to that of the first image sliding across the screen. Please help.
Full code is linked here: https://code.sololearn.com/Wwdw59oenFqB
<!DOCTYPE html>
<html lang="en">
<head>
<title>Test</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
zoom: 25%
}
.circle {
display: block;
background: black;
border-radius: 100%;
height: 100px;
width: 100px;
background: radial-gradient(circle at center,#31f541, #000);
}
.container {
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.circle-image{
z-index: 2;
position: absolute;
margin-left: 50%;
margin-top: 50vh;
border-radius: 50%;
}
</style>
</head>
<body>
<div class="container">
<img id = "firstImage" style = "height: 1000px; width: 1000px;" onclick = "change(); clickCounter(); animate(); saveData();"class="circle-image" src="data:image/jpeg;base64,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">
<img id = "secondImage" style = "height: 1000px; width: 1000px;" onclick = "animate();"class="circle-image" src="https://en.meming.world/images/en/thumb/e/e2/Crying_Cat_screaming.jpg/300px-Crying_Cat_screaming.jpg">
<p style = "transform: scale(10, 10);"id = "clicker">Kitten has been pat: <a id="clickCounter">0</a> times in <a id = "timeCounter">0</a> seconds</p>
<figure class="circle"></figure>
</div>
<button onclick = "saveData();"id = "saveButton">Load progress</button>
<script>
const cats = [];
for(i = 0; i < 10; i++){
var img = document.createElement("img");
img.setAttribute("src", "data:image/jpeg;base64,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");
img.className = "catSwarm"
img.addEventListener('click', function handleClick(event) {
change(); clickCounter();
});
img.addEventListener('load', function handleClick(event) {
})
document.body.appendChild(img);
cats.push(img)
}
let clicks = 0;
function clickCounter() {
clicks += 1;
document.getElementById("clickCounter").innerHTML = clicks;
if (clicks != 10) {
}
else {
alert("Kitten has been pet 10 times")
}
};
let time = 0;
function timeCounter() {
time+=1
document.getElementById("timeCounter").innerHTML = time;
setTimeout(timeCounter, 1000)
if(time != 10) {
}
else{
setTimeout(function() {
alert ("Kitten has been pet " + clicks + " times in " + time + " seconds" + " with a whopping pats per second rate of " + clicks/time + "!")
}, 10);
}}
timeCounter();
function change() {
if(document.getElementById("firstImage").style.src = "data:image/jpeg;base64,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") {
document.getElementById("firstImage").src = "https://en.meming.world/images/en/thumb/e/e2/Crying_Cat_screaming.jpg/300px-Crying_Cat_screaming.jpg";
}
else {document.getElementById("firstImage").style.src = "data:image/jpeg;base64,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"> {
}
}}
function saveData() {
if (typeof(Storage) !== "undefined") {
if (localStorage.clickcount) {
localStorage.clickcount = Number(localStorage.clickcount)+1;
} else {
localStorage.clickcount = 1;
}
document.querySelector("p").innerText = "Kitten has been pat: " + localStorage.clickcount + " times in " + time + " seconds";
}
}
const fps = 25;
let image = document.querySelector("img");
let angle = Math.PI / 2;
//store the previous time the animate function last fired
let prevTimeArg;
function animate(currentTimeParam){
if (prevTimeArg != null) {
angle += (currentTimeParam - prevTimeArg) * 0.004;
}
// Setting the previous time to the time the function currently fires
prevTimeArg = currentTimeParam ;
image.style.top = (Math.tan(angle) * 150) + "px";
image.style.left = (Math.tan(angle) * 150) + "px";
image.style.height = (Math.cos(angle) * 1000) + "px";
image.style.width = (Math.cos(angle) * 1000) + "px";
setTimeout(() => {
requestAnimationFrame(currentTime => animate(currentTime));
}, 0 / fps)}
for (i = 0; i < cats.length; i++) {
window.requestAnimationFrame(animate);
}
</script>
</body>
</html>
Thank you in advance..
I have an API list and I want my divs to float within this huge container. this is my reference - but for some reason this doesn't work for mine (http://jsfiddle.net/bsd3b0r0/1/) I know I'm probably missing something, naming of my divs or something but I simply cannot figure it out. Would appreciate any advice.
/* globals require */
console.log("Hello, Airtable");
let wrapper = document.querySelector(".container");
// load the airtable library, call it "Airtable"
let Airtable = require("airtable");
console.log(Airtable);
// use the airtable library, connect to our base using API key
let base = new Airtable({ apiKey: "keyXfgdNIcv7dW63l" }).base(
"appWiQM0htfVBj9RL"
);
//get the "books" table from the base, select ALL the records, and specify the functions that will receive the data
base("nature_sounds").select({}).eachPage(gotPageOfSounds, gotAllSounds);
// an empty array to hold our book data
let sounds = [];
// callback function that receives our data
function gotPageOfSounds(records, fetchNextPage) {
console.log("gotPageOfSounds()");
// add the records from this page to our books array
sounds.push(...records);
// request more pages
fetchNextPage();
}
// call back function that is called when all pages are loaded
function gotAllSounds(err) {
console.log("gotAllSounds()");
// report an error, you'd want to do something better than this in production
if (err) {
console.log("error loading sounds");
console.error(err);
return;
}
// call functions to log and show the books
consoleLogSounds();
showSounds();
}
// just loop through the books and console.log them
function consoleLogSounds() {
console.log("consoleLogSounds()");
sounds.forEach((sound) => {
console.log("Sound:", sound);
});
}
// loop through the books, create an h2 for each one, and add it to the page
function showSounds() {
console.log("showSounds()");
sounds.forEach((sound) => {
let soundTextHolder = document.createElement("div"); // victoria u changed it from h2 to div dont forget//
soundTextHolder.classList.add("entry");
soundTextHolder.innerText = sound.fields.emotion;
wrapper.appendChild(soundTextHolder);
let soundColor = sound.fields.color_hex_code;
soundTextHolder.style.backgroundColor = soundColor;
let audioHolder = document.createElement("audio");
audioHolder.src = sound.fields.audio_file[0].url;
audioHolder.classList.add("soundClass");
audioHolder.controls = true;
audioHolder.autoplay = true;
audioHolder.loop = true;
soundTextHolder.appendChild(audioHolder);
});
}
// trying to aniamte//
var divsize = 5,
divcount = 50;
var gRows = Math.floor($(".container").innerWidth() / divsize);
var gCols = Math.floor($('.container').innerHeight() / divsize);
var vals = _.shuffle(_.range(divcount));
var xpos = _.shuffle(_.range(gRows));
var ypos = _.shuffle(_.range(gCols));
_.each(vals, function(d, i) {
var $newdiv = $('<div/>').addClass("div");
$newdiv.css({
'position': 'absolute',
'left': (xpos[i] * divsize) + 'px',
'top': (ypos[i] * divsize) + 'px'
}).appendTo('.container').html(d);
animateDiv();
});
function newPosition() {
// Get viewport dimensions (remove the dimension of the div)
var h = $('.container').height() - 50;
var w = $('.container').width() - 50;
var newh = Math.floor(Math.random() * h);
var neww = Math.floor(Math.random() * w);
return [newh, neww];
}
function animateDiv() {
var newp = newPosition();
var oldp = $('div').offset();
var speed = 3000;
$('div').animate({
top: newp[0],
left: newp[1]
}, speed, function() {
animateDiv();
});
};
// // // collect all the divs
// var divs = document.getElementsByTagName('h2');
// // // get window width and height
// / var winWidth = window.innerWidth;
// / var winHeight = window.innerHeight;
// // // i stands for "index". you could also call this banana or haircut. it's a variable
// // for ( var i=0; i < divs.length; i++ ) {
// // // shortcut! the current div in the list
// // var thisDiv = divs[i];
// // // get random numbers for each element
// // randomTop = getRandomNumber(0, winHeight);
// // randomLeft = getRandomNumber(0, winWidth);
// // // update top and left position
// / thisDiv.style.top = randomTop +"px";
// / thisDiv.style.left = randomLeft +"px";
// }
// // function that returns a random number between a min and max
// function getRandomNumber(min, max) {
// return Math.random() * (max - min) + min;
// }
body{
font-family: Space Mono;
background-color: white;
}
h1{
text-align: right;
color: black;
font-family: sans-serif;
}
.container{
width: 100%;
/* align-items: center;
display: grid;
grid-row: inherit;
position: relative; */
}
div{
border-radius: 50% 20% / 10% 40%;
/* border-radius: 10% / 50%; */
width: 30vw;
margin-left: auto;
margin-right: auto;
text-align: center;
/* display: flex; */
flex-direction: column;
box-shadow: inset 0 0 2000px rgba(255, 255, 255, .5);
filter: blur(1px);
/* animation-name: floating;
animation-duration: 3s;
animation-iteration-count: infinite;
animation-timing-function: ease-in-out; */
}
/* #keyframes floating {
0% { transform: translate(0, 0px); }
50% { transform: translate(0, 15px); }
100% { transform: translate(0, -0px); }
} */
.entry1{
width: 60vw;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>EllasticCollection</title>
<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=Space+Mono&display=swap" rel="stylesheet">
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>sound and color through emotion</h1>
<div id="myData" class="container">
<div class="individual-colors"></div>
</div>
<script src="airtable.browser.js" defer></script>
<script src="script.js" defer></script>
</body>
</html>
I have a 11500x11500 div that consists of 400 images, that obviously overflows the viewport.
I would like to pan around the whole div programmatically.
I want to generate an animation and by the time the animation is over, the whole of the div must have been panned across the viewport, top to bottom, left to right.
Right now, I am "splitting" my 11500x1500 div into tiles. The maximum width and height of each tile is the width and height of the viewport.
I store the coordinates of each tile and then I randomly choose one, pan it left-to-right and then move on to the next one.
I would like to know:
whether my method is correct or whether I am missing something in my calculations/approach and it could be improved. Given the size, it is hard for me to tell whether I'm actually panning the whole of the div after all
whether I can make the panning effect feel more "organic"/"natural". In order to be sure that the whole div is eventually panned, I pick each tile and pan it left-to-right, move on to the next one etc. This feels kind of rigid and too formalised. Is there a way to pan at let's say an angle or with a movement that is even more random and yet be sure that the whole div will eventually be panned ?
Thank in advance for any help.
This is the jsfiddle and this is the code (for the sake of the example/test every "image" is actually a div containing its index as text):
function forMs(time) {
return new Promise((resolve) => {
setTimeout(() => {
resolve()
}, time)
})
}
let container = document.getElementById('container')
let {
width,
height
} = container.getBoundingClientRect()
let minLeft = window.innerWidth - width
let minTop = window.innerHeight - height
let i = 0
while (i < 400) {
// adding "image" to the container
let image = document.createElement('div')
// add some text to the "image"
// to know what we're looking at while panning
image.innerHTML = ''
let j = 0
while (j < 100) {
image.innerHTML += ` ${i + 1}`
j++
}
container.appendChild(image)
i++
}
let coords = []
let x = 0
while (x < width) {
let y = 0
while (y < height) {
coords.push({
x,
y
})
y += window.innerHeight
}
x += window.innerWidth
}
async function pan() {
if (!coords.length) {
return;
}
let randomIdx = Math.floor(Math.random() * coords.length)
let [randomCoord] = coords.splice(randomIdx, 1);
console.log(coords.length)
container.classList.add('fast')
// update style in new thread so new transition-duration is applied
await forMs(10)
// move to new yet-unpanned area
container.style.top = Math.max(-randomCoord.y, minTop) + 'px'
container.style.left = Math.max(-randomCoord.x, minLeft) + 'px'
// wait (approx.) for transition to end
await forMs(2500)
container.classList.remove('fast')
// update style in new thread so new transition-duration is applied
await forMs(10)
//pan that area
let newLeft = -(randomCoord.x + window.innerWidth)
if (newLeft < minLeft) {
newLeft = minLeft
}
container.style.left = newLeft + 'px'
// wait (approx.) for transition to end
await forMs(4500)
// move on to next random area
await pan()
}
pan()
html,
body {
position: relative;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: auto;
}
* {
margin: 0;
padding: 0;
}
#container {
position: absolute;
top: 0;
left: 0;
text-align: left;
width: 11500px;
height: 11500px;
transition: all 4s ease-in-out;
transition-property: top left;
font-size: 0;
}
#container.fast {
transition-duration: 2s;
}
#container div {
display: inline-block;
height: 575px;
width: 575px;
border: 1px solid black;
box-sizing: border-box;
font-size: 45px;
overflow: hidden;
word-break: break-all;
}
<div id="container"></div>
I think following improvements can be made:
Hide overflow on html and body so user can not move scrollbar and disturb the flow.
Calculate minLeft and minTop every time to account for window resizing. You might need ResizeObserver to recalculate things.
Increase transition times to avoid Cybersickness. In worse case RNG will pick bottom right tile first so your container will move the longest in 2seconds! Maybe, you can zoom-out and move then zoom-in then perform pan. Or use any serpentine path which will make shorter jumps.
Performance improvements:
Use transform instead of top, left for animation.
Use will-change: transform;. will-change will let browser know what to optimize.
Use translate3D() instead of translate(). ref
Use requestAnimationFrame. Avoid setTimeout, setInterval.
This is an old but good article: https://www.paulirish.com/2012/why-moving-elements-with-translate-is-better-than-posabs-topleft/
Modified code to use transform:
function forMs(time) {
return new Promise((resolve) => {
setTimeout(() => {
resolve()
}, time)
})
}
let container = document.getElementById('container')
let stat = document.getElementById('stats');
let {
width,
height
} = container.getBoundingClientRect()
let minLeft = window.innerWidth - width
let minTop = window.innerHeight - height
let i = 0
while (i < 400) {
// adding "image" to the container
let image = document.createElement('div')
// add some text to the "image"
// to know what we're looking at while panning
image.innerHTML = ''
let j = 0
while (j < 100) {
image.innerHTML += ` ${i + 1}`
j++
}
container.appendChild(image)
i++
}
let coords = []
let x = 0
while (x < width) {
let y = 0
while (y < height) {
coords.push({
x,
y
})
y += window.innerHeight
}
x += window.innerWidth
}
let count = 0;
async function pan() {
if (!coords.length) {
stat.innerText = 'iteration: ' +
(++count) + '\n tile# ' + randomIdx + ' done!!';
stat.style.backgroundColor = 'red';
return;
}
let minLeft = window.innerWidth - width
let minTop = window.innerHeight - height
let randomIdx = Math.floor(Math.random() * coords.length);
randomIdx = 1; //remove after debugging
let [randomCoord] = coords.splice(randomIdx, 1);
stat.innerText = 'iteration: ' +
(++count) + '\n tile# ' + randomIdx;
console.log(coords.length + ' - ' + randomIdx)
container.classList.add('fast')
// update style in new thread so new transition-duration is applied
await forMs(10)
// move to new yet-unpanned area
let yy = Math.max(-randomCoord.y, minTop);
let xx = Math.max(-randomCoord.x, minLeft);
move(xx, yy);
// wait (approx.) for transition to end
await forMs(2500)
container.classList.remove('fast')
// update style in new thread so new transition-duration is applied
await forMs(10)
//pan that area
let newLeft = -(randomCoord.x + window.innerWidth)
if (newLeft < minLeft) {
newLeft = minLeft
}
xx = newLeft;
//container.style.left = newLeft + 'px'
move(xx, yy);
// wait (approx.) for transition to end
await forMs(4500)
// move on to next random area
await pan()
}
pan()
function move(xx, yy) {
container.style.transform = "translate3D(" + xx + "px," + yy + "px,0px)";
}
html,
body {
position: relative;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
#container {
text-align: left;
width: 11500px;
height: 11500px;
transition: all 4s ease-in-out;
transition-property: transform;
font-size: 0;
will-change: transform;
}
#container.fast {
transition-duration: 2s;
}
#container div {
display: inline-block;
height: 575px;
width: 575px;
border: 1px solid black;
box-sizing: border-box;
font-size: 45px;
overflow: hidden;
word-break: break-all;
}
#stats {
border: 2px solid green;
width: 100px;
background-color: lightgreen;
position: fixed;
opacity: 1;
top: 0;
left: 0;
z-index: 10;
}
<div id=stats>iteration: 1 tile# 11</div>
<div id="container"></div>
Note I haven't implemented everything in above snippet.
I've been working on a project using jQuery where i have a div element that says "click," and when you try to click on it, it moves to a random location within the window. The issue I'm having is that every once in a while the div will move only a little bit, leaving the cursor still inside of the div, allowing the user to click on the link.
I'm fairly new at javascript and I'm not too sure how I should go about doing something like this.
I was thinking I could do something like subtracting the new position from the old one and checking to see if they have a difference of less than 200px, and if they do, recalculating the numbers. If that isn't how you would do it, I'm completely open to other methods.
function setPosition() {
var randY = Math.floor(Math.random() * (window.innerHeight - 200));
var randX = Math.floor(Math.random() * (window.innerWidth - 200));
$('#square').animate({
top: randY + 'px',
left: randX + 'px'
}, 200);
}
$(document).ready(function() {
setPosition()
var tries = 0;
//tries is just to stop it after it reaches 1000.
//I'm planning to make some kind of page to congradulate you on wasting your time.
$('#square').mouseenter(function() {
if (tries < 1000) {
setPosition();
tries += 1;
console.log(tries)
}
});
});
#square {
background: orange;
height: 115px;
width: 150px;
position: relative;
text-align: center;
padding-top: 35px;
}
h3,
h3 * {
font-family: "Comic Sans MS", cursive, sans-serif;
font-size: 20px;
vertical-align: middle;
position: relative;
color: black;
text-decoration: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
<head>
<link rel=stylesheet type=text/css href=square.css>
<script src=jquery-1.11.3.min.js></script>
<script src=square.js></script>
</head>
<body>
<div id=square>
<h3><a href=''>Click</a></h3>
</div>
</body>
</html>
I'm thinking you might want to run your randomization logic until it finds a combination that is more than 200 pixels away from it's current location.
Off the top of my head, that'd be something like this:
function setPosition() {
var $square = $('#square');
var prevY = $square.offset().top;
var prevX = $square.offset().left;
var randY, randX;
do {
randY = Math.floor(Math.random() * (window.innerHeight - 200));
randX = Math.floor(Math.random() * (window.innerWidth - 200));
} while( Math.abs(randY - prevY) < 200 || Math.abs(randX - prevX) < 200 );
$square.animate({
top: randY + 'px',
left: randX + 'px'
}, 200);
}
I'm using the PDF.js library to render a pdf into the canvas. That pdf has hyperlinks in there, The PDF.js library is drawing the pdf into the canvas but the hyperlinks don't work.
Any Idea if it possible that hyperlinks work into the canvas?
Thanks
Here is a fiddle that shows you how to enable annotations (including hyperlinks) in PDF files.
The original PDF file used in the fiddle is here.
I used viewer code (web/page_view.js,web/viewer.css) as refrence to write this fiddle.
HTML:
<!doctype html>
<html lang="en">
<head>
<link href="style.css" rel="stylesheet" media="screen" />
<script src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
<script src="http://seikichi.github.io/tmp/PDFJS.0.8.715/pdf.min.js" type="text/javascript"></script>
<script src="http://seikichi.github.io/tmp/PDFJS.0.8.715/ui_utils.js"></script>
<script src="./main.js" type="text/javascript"></script>
</head>
<body>
<div id="pdfContainer" class="pdf-content">
<canvas id="the-canvas"></canvas>
<div class="annotationLayer"></div>
</div>
</body>
</html>
CSS:
body {
font-family: arial, verdana, sans-serif;
}
.pdf-content {
border: 1px solid #000000;
}
.annotationLayer > a {
display: block;
position: absolute;
}
.annotationLayer > a:hover {
opacity: 0.2;
background: #ff0;
box-shadow: 0px 2px 10px #ff0;
}
.annotText > div {
z-index: 200;
position: absolute;
padding: 0.6em;
max-width: 20em;
background-color: #FFFF99;
box-shadow: 0px 2px 10px #333;
border-radius: 7px;
}
.annotText > img {
position: absolute;
opacity: 0.6;
}
.annotText > img:hover {
opacity: 1;
}
.annotText > div > h1 {
font-size: 1.2em;
border-bottom: 1px solid #000000;
margin: 0px;
}
JavaScript:
PDFJS.workerSrc = 'http://seikichi.github.io/tmp/PDFJS.0.8.715/pdf.min.worker.js';
$(function () {
var pdfData = loadPDFData();
PDFJS.getDocument(pdfData).then(function (pdf) {
return pdf.getPage(1);
}).then(function (page) {
var scale = 1;
var viewport = page.getViewport(scale);
var $canvas = $('#the-canvas');
var canvas = $canvas.get(0);
var context = canvas.getContext("2d");
canvas.height = viewport.height;
canvas.width = viewport.width;
var $pdfContainer = $("#pdfContainer");
$pdfContainer.css("height", canvas.height + "px")
.css("width", canvas.width + "px");
var renderContext = {
canvasContext: context,
viewport: viewport
};
page.render(renderContext);
setupAnnotations(page, viewport, canvas, $('.annotationLayer'));
});
function setupAnnotations(page, viewport, canvas, $annotationLayerDiv) {
var canvasOffset = $(canvas).offset();
var promise = page.getAnnotations().then(function (annotationsData) {
viewport = viewport.clone({
dontFlip: true
});
for (var i = 0; i < annotationsData.length; i++) {
var data = annotationsData[i];
var annotation = PDFJS.Annotation.fromData(data);
if (!annotation || !annotation.hasHtml()) {
continue;
}
var element = annotation.getHtmlElement(page.commonObjs);
data = annotation.getData();
var rect = data.rect;
var view = page.view;
rect = PDFJS.Util.normalizeRect([
rect[0],
view[3] - rect[1] + view[1],
rect[2],
view[3] - rect[3] + view[1]]);
element.style.left = (canvasOffset.left + rect[0]) + 'px';
element.style.top = (canvasOffset.top + rect[1]) + 'px';
element.style.position = 'absolute';
var transform = viewport.transform;
var transformStr = 'matrix(' + transform.join(',') + ')';
CustomStyle.setProp('transform', element, transformStr);
var transformOriginStr = -rect[0] + 'px ' + -rect[1] + 'px';
CustomStyle.setProp('transformOrigin', element, transformOriginStr);
if (data.subtype === 'Link' && !data.url) {
// In this example, I do not handle the `Link` annotations without url.
// If you want to handle those annotations, see `web/page_view.js`.
continue;
}
$annotationLayerDiv.append(element);
}
});
return promise;
}
});
function loadPDFData() {
/*jshint multistr: true */
var base64pdfData = '...'; //should contain base64 representing the PDF
function base64ToUint8Array(base64) {
var raw = atob(base64);
var uint8Array = new Uint8Array(new ArrayBuffer(raw.length));
for (var i = 0, len = raw.length; i < len; ++i) {
uint8Array[i] = raw.charCodeAt(i);
}
return uint8Array;
}
return base64ToUint8Array(base64pdfData);
}
Enable Text Selection in PDF.JS
Step 1: Adding a Element to Hold the Text Layer
<div id="text-layer"></div>
This div will be in addition to the element where the PDF is rendered, so the HTML will look like :
<canvas id="pdf-canvas"></canvas>
<div id="text-layer"></div>
Step 2 : Adding CSS for Text Layer
Add the following to your CSS file :
#text-layer {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
overflow: hidden;
opacity: 0.2;
line-height: 1.0;
}
#text-layer > div {
color: transparent;
position: absolute;
white-space: pre;
cursor: text;
transform-origin: 0% 0%;
}
Step 3: Getting the PDF Text
After the PDF has been rendered in the canvas, you need to get the text contents of the PDF, and place that text in the text layer.
// page is the page context of the PDF page
// viewport is the viewport required in renderContext
// For more see https://usefulangle.com/post/20/pdfjs-tutorial-1-preview-pdf-during-upload-wih-next-prev-buttons
page.render(renderContext).then(function() {
// Returns a promise, on resolving it will return text contents of the page
return page.getTextContent();
}).then(function(textContent) {
// PDF canvas
var pdf_canvas = $("#pdf-canvas");
// Canvas offset
var canvas_offset = pdf_canvas.offset();
// Canvas height
var canvas_height = pdf_canvas.get(0).height;
// Canvas width
var canvas_width = pdf_canvas.get(0).width;
// Assign CSS to the text-layer element
$("#text-layer").css({ left: canvas_offset.left + 'px', top: canvas_offset.top + 'px', height: canvas_height + 'px', width: canvas_width + 'px' });
// Pass the data to the method for rendering of text over the pdf canvas.
PDFJS.renderTextLayer({
textContent: textContent,
container: $("#text-layer").get(0),
viewport: viewport,
textDivs: []
});
});
source: https://usefulangle.com/post/90/javascript-pdfjs-enable-text-layer
setupAnnotations = (page, viewport, canvas, annotationLayerDiv) => {
let pdfjsLib = window['pdfjs-dist/build/pdf'];
let pdfjsViewer = window['pdfjs-dist/web/pdf_viewer'];
//BELOW--------- Create Link Service using pdf viewer
let pdfLinkService = new pdfjsViewer.PDFLinkService();
page.getAnnotations().then(function (annotationsData) {
viewport = viewport.clone({
dontFlip: true
});
let pdf_canvas = canvas;
// Render the annotation layer
annotationLayerDiv.style.left = pdf_canvas.offsetLeft + 'px';
annotationLayerDiv.style.top = pdf_canvas.offsetTop + 'px';
annotationLayerDiv.style.height = viewport.height + 'px';
annotationLayerDiv.style.width = viewport.width + 'px';
pdfjsLib.AnnotationLayer.render({
viewport: viewport,
div: annotationLayerDiv,
annotations: annotationsData,
page: page,
linkService: pdfLinkService,
enableScripting: true,
renderInteractiveForms: true
});
}
IMP ---- Do not forget to add this CSS
.annotation-layer{
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
overflow: hidden;
opacity: 1;
}
.annotation-layer section{
position: absolute;
cursor: pointer;
}
.annotation-layer section a{
display: block;
width: 100%;
height: 10px;
}
In above example, Link service instance is created using class in pdf viewer, which is being passed as parameter to annotation layer render method.
Please refer source code of PDF.js refer to /web/pdf_viewer.js - class PDFLinkService for more information.
PDF.js version - v2.9.359