i have created a p5.js sketch and tried to implement it on my website as a loader… the problem is, that i have to load the p5.js sketch in the body part of my HTML because the sketch would still be visible after loading the page, if i put it in the head…
<body onload="myLoader()" style="margin:0;">
<div id="loader">
<script src="sketch-loader.js"></script>
</div>
<div style="display:none;" id="myDiv" class="animate-bottom">
//content of my website
</div>
<script>
var myVar;
function myLoader() {
myVar = setTimeout(showPage, 3000);
}
function showPage() {
document.getElementById("loader").style.display = "none";
document.getElementById("myDiv").style.display = "block";
}
</script>
</body>
@micuat is spot on that you are not actually attaching the p5js canvas to the “loader” div. And there are several ways to fix that, one is using parent property, another is using instance mode via the p5 constructor, which takes an argument specifying the parent element for the canvas.
However, one other thing that bears noting, just hiding the div is potentially still going to leave the p5js sketch running and consuming resources. You would do well to also call remove() to completely stop the sketch.
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.min.js"></script>
<style>
#loading_screen {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
body.loaded #loading_screen {
display: none;
}
</style>
<!-- if you include other heafty javascript files here, use the defer attribute -->
</head>
<body>
<div id="root">
<!-- this is where your SPA content will show up -->
NOTHING TO SEE HERE YET
</div>
<div id="loading_screen">
<!-- this is where the p5js loading screen canvas will be -->
</div>
<script>
function LoadingScreen(p) {
p.setup = function() {
p.createCanvas(p.windowWidth, p.windowHeight);
}
p.draw = function() {
p.background(200, 200, 200, 20);
p.circle(
p.width / 2 + p.cos(p.millis() / 400) * 100,
p.height / 2 + p.sin(p.millis() / 400) * 100,
100
);
}
}
let sketch = new p5(LoadingScreen, 'loading_screen');
document.addEventListener('appLoaded', () => {
// Make the loading screen go away
sketch.remove(); // This removes the canvas
document.body.classList.add('loaded'); // This stops displaying the div
});
</script>
<script>
<!-- Imagine this is some script that runs once your app is done bootstrapping
-->
<!-- Where exactly this code goes depends on your SPA framework -->
setTimeout(
() => {
let root = document.getElementById('root');
root.innerHTML = 'Hooray our app has loaded!';
document.dispatchEvent(new CustomEvent('appLoaded'));
},
5000 // simulate the app taking 5 seconds to load
);
</script>
</body>
</html>
Hi @KumuPaul
Yeah that’s exactly what i tried to do! Thank you so much for your help!
I have only one Question: Where should I put the content of my Website?
Because if I put it in the root div its only visible before the loader appears
<div id="root">
<!-- this is where your SPA content will show up -->
NOTHING TO SEE HERE YET
</div>
Because everything I put here overlaps with the root div:
root.innerHTML = 'Hooray our app has loaded!';
and I have too much content to put everything in the innerHTML function…
I tried to implement the code of @KumuPaul in my website but i have still 3 issues with it…
I tried to implement my p5.js sketch into your script tag, but made a some bugs in doing so… where should i put the p. if i have a variable in front of it?
myText.p.splice(space, 0, '');
I have a second p5.js sketch, which should display when the site is loaded… i tried to put it in the head section with the defer attribute, somehow it doesn’t work everytime i reload…
I have an Accordion, which broke when I tried to implement your code… somehow it works if I resize the screen…
If you could help me again with these issues I would be soo thankful!
When using p5js in instance mode you only need to use the p variable when accessing global/static p5.js functions and constants (like createCanvas() or text() or width). It looks like you’re conflating the p5.js static splice function and the built in javascript instance function on arrays. It also looks like you may be trying to use splice with a string which won’t work since it only works on arrays. And the p5.js splice function is deprecated in any case.
Is your project hosted on Glitch? I saw a glitch cdn URL in there which is why I ask. If you can share a link to your project I might be able to help you out (I’m @KumuPaul on glitch if it’s private).
Yeah i tried to uploaded it on github, but i’m not sure how it will work because its made with Kirby CMS…
but sent you an invitation if you want to have a look
Ugh, I hate CMSs, they’re all terrible. Here you go:
Things I had to change:
Moved the loading screen div and the loading screen script up to the top of the file.
this is important because the browser loads page content in linear order, and you want that loading screen to show up ASAP.
Inlined the loading screen sketch into the loading screen script block:
<!-- Put this at the top of the body so it is loaded and executed first thing -->
<div id="loading_screen">
<!-- this is where the p5js loading screen canvas will be -->
</div>
<script>
console.log(`${new Date()} starting loading screen...`);
function loadingScreen(p) {
let font;
let space;
let amount = 40;
let state = [amount];
let myText = ["C", "I", "A", "N", "", "J", "O", "C", "H", "E", "M"];
p.preload = function() {
console.log(`${new Date()} Preloading font`);
font = p.loadFont(
"https://cdn.glitch.com/ba7ae563-6481-4d92-8b25-48f6cd661df0%2FEverettMono-Regular-web.ttf?v=1617819670199"
);
};
p.setup = function() {
p.createCanvas(p.windowWidth, p.windowHeight);
p.background(247);
p.frameRate(10);
console.log(`${new Date()} Loading screen setup complete`);
};
p.draw = function() {
p.background(247, 20);
p.textFont(font);
p.fill(0);
p.textSize(16);
myText = ["C", "I", "A", "N", "", "J", "O", "C", "H", "E", "M"];
for (let i = 0; i < 29; i++) {
space = p.floor(p.random(1, 11 + i));
myText.splice(space, 0, "");
}
let tileW = (p.width - 80) / amount;
for (let x = 0; x < amount; x++) {
p.push();
p.translate(40 + x * tileW, 60 + (p.frameCount % 30) * 30);
p.text(myText[x], 0, 0);
p.pop();
}
};
}
let sketch = new p5(loadingScreen, "loading_screen");
document.addEventListener("appLoaded", () => {
sketch.remove(); // This removes the loading screen canvas
});
</script>
Converted the header sketch to also be an instance mode sketch and inlined it into the script block at the end of the file:
console.log(`${new Date()} creating loading timeout.`);
setTimeout(
() => {
console.log(`${new Date()} loading complete.`);
// Signal the loading sketch to stop, and the header sketch to start
document.dispatchEvent(new CustomEvent("appLoaded"));
// Stop displaying the loading div, start displaying the content
document.body.classList.add("loaded");
},
7000 // simulate the app taking 7 seconds to load
);
function headerSketch(p) {
let font;
let space;
let myCanvas;
let amount = 40;
let myText = ["C", "I", "A", "N", "", "J", "O", "C", "H", "E", "M"];
p.preload = function() {
font = p.loadFont(
"https://cdn.glitch.com/ba7ae563-6481-4d92-8b25-48f6cd661df0%2FEverettMono-Regular-web.ttf?v=1617819670199"
);
};
p.setup = function() {
myCanvas = p.createCanvas(p.windowWidth, p.windowHeight);
myCanvas.position(40, 0);
myCanvas.style("z-index", "-999");
for (let i = 0; i < 29; i++) {
if (p.mouseX < p.width / 2) {
space = p.floor(p.random(1, 11 + i));
} else if (p.mouseX > p.width / 2) {
space = p.floor(p.random(1, 11 + i));
}
myText.splice(space, 0, "");
}
};
p.draw = function() {
p.background(247, 50);
p.textFont(font);
p.fill(0);
p.textSize(16);
let tileW = (p.width - 80) / amount;
for (let x = 0; x < amount; x++) {
p.push();
p.translate(x * tileW, 60);
p.text(myText[x], 0, 0);
p.pop();
}
};
p.windowResized = function() {
p.resizeCanvas(p.windowWidth, p.windowHeight);
};
}
let header = new p5(headerSketch, "header");
For some reason I haven’t been able to determine, p5.js sometimes takes its sweet time getting the loading screen up and running. I’m not sure what can be done about that.
Oh, I forgot, I made some tweaks to the CSS as well.
#loading_screen {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
body.loaded #loading_screen {
display: none;
}
/* Use the loaded CSS class for everything instead of manipulating styles.
This simplifies the code and makes it easier to customize the display with
alternate stylesheets (i.e. for printing) */
body:not(.loaded) #content {
/* Use visibility instead of display because I think the browser does more
of the layout work if with visibility: hidden. With display: none it might
just ignore the content completely. Not 100% sure about this though. */
visibility: hidden;
}
body.loaded #content {
visibility: visible;
}