How to set a script as Background of a concrete <section>? - javascript

I am using Bootstrap for a one-page website project. This website is divided in 4 parts, each one inside a 'section' with its own background color/image and content.
For one of these sections (the first one), which occupies the whole screen and has a 'Navbar' at the top and some headers inside, I would like to set a script as the background and not a simple image or solid color as in the other sections.
For this, I would like to know how to set a JavaScript code as the background, without affecting any other item inside the same section and being able to see the text over this background element.
This is the concrete script that I would like to set as background (got it from codePen.io): http://jsfiddle.net/oleg_korol/a1bxr5ua/1/
Here is the code:
var w = c.width = window.innerWidth,
h = c.height = window.innerHeight,
ctx = c.getContext('2d'),
opts = {
len: 20,
count: 50,
baseTime: 10,
addedTime: 10,
dieChance: .05,
spawnChance: 1,
sparkChance: .1,
sparkDist: 10,
sparkSize: 2,
color: 'hsl(hue,100%,light%)',
baseLight: 50,
addedLight: 10, // [50-10,50+10]
shadowToTimePropMult: 6,
baseLightInputMultiplier: .01,
addedLightInputMultiplier: .02,
cx: w / 2,
cy: h / 2,
repaintAlpha: .04,
hueChange: .1
},
tick = 0,
lines = [],
dieX = w / 2 / opts.len,
dieY = h / 2 / opts.len,
baseRad = Math.PI * 2 / 6;
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, w, h);
function loop() {
window.requestAnimationFrame(loop);
++tick;
ctx.globalCompositeOperation = 'source-over';
ctx.shadowBlur = 0;
ctx.fillStyle = 'rgba(0,0,0,alp)'.replace('alp', opts.repaintAlpha);
ctx.fillRect(0, 0, w, h);
ctx.globalCompositeOperation = 'lighter';
if (lines.length < opts.count && Math.random() < opts.spawnChance) lines.push(new Line);
lines.map(function (line) {
line.step();
});
}
function Line() {
this.reset();
}
Line.prototype.reset = function () {
this.x = 0;
this.y = 0;
this.addedX = 0;
this.addedY = 0;
this.rad = 0;
this.lightInputMultiplier = opts.baseLightInputMultiplier + opts.addedLightInputMultiplier * Math.random();
this.color = opts.color.replace('hue', tick * opts.hueChange);
this.cumulativeTime = 0;
this.beginPhase();
}
Line.prototype.beginPhase = function () {
this.x += this.addedX;
this.y += this.addedY;
this.time = 0;
this.targetTime = (opts.baseTime + opts.addedTime * Math.random()) | 0;
this.rad += baseRad * (Math.random() < .5 ? 1 : -1);
this.addedX = Math.cos(this.rad);
this.addedY = Math.sin(this.rad);
if (Math.random() < opts.dieChance || this.x > dieX || this.x < -dieX || this.y > dieY || this.y < -dieY) this.reset();
}
Line.prototype.step = function () {
++this.time;
++this.cumulativeTime;
if (this.time >= this.targetTime) this.beginPhase();
var prop = this.time / this.targetTime,
wave = Math.sin(prop * Math.PI / 2),
x = this.addedX * wave,
y = this.addedY * wave;
ctx.shadowBlur = prop * opts.shadowToTimePropMult;
ctx.fillStyle = ctx.shadowColor = this.color.replace('light', opts.baseLight + opts.addedLight * Math.sin(this.cumulativeTime * this.lightInputMultiplier));
ctx.fillRect(opts.cx + (this.x + x) * opts.len, opts.cy + (this.y + y) * opts.len, 2, 2);
if (Math.random() < opts.sparkChance) ctx.fillRect(opts.cx + (this.x + x) * opts.len + Math.random() * opts.sparkDist * (Math.random() < .5 ? 1 : -1) - opts.sparkSize / 2, opts.cy + (this.y + y) * opts.len + Math.random() * opts.sparkDist * (Math.random() < .5 ? 1 : -1) - opts.sparkSize / 2, opts.sparkSize, opts.sparkSize)
}
loop();
window.addEventListener('resize', function () {
w = c.width = window.innerWidth;
h = c.height = window.innerHeight;
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, w, h);
opts.cx = w / 2;
opts.cy = h / 2;
dieX = w / 2 / opts.len;
dieY = h / 2 / opts.len;
});
//# sourceURL=pen.js
Thanks a lot!
Original piece of code from: http://codepen.io/towc/pen/mJzOWJ
by Matei Copot

You can do this using an iframe and placing it as an absolute element with full body width and height like this:
HTML:
<body>
<div id="iframe"><iframe name="result" sandbox="allow-forms allow-popups allow-scripts allow-same-origin" frameborder="0" src="//fiddle.jshell.net/oleg_korol/a1bxr5ua/1/show/"></iframe></div>
<!--Your page content-->
</body>
CSS:
html, body {
margin:0px;
width:100%;
height:100%;
overflow:hidden;
}
iframe {
width:100%;
height:100%;
}
#iframe {
position: absolute;
float: left;
clear: both;
width: 100%;
height: 100%;
z-index: 0;
}
Here is a jsfiddle with above codes: https://jsfiddle.net/AndrewL32/kkLLxkxk/2/
And here is a StackOverflow snippet with above codes:
html, body {
margin:0px;
width:100%;
height:100%;
overflow:hidden;
}
iframe {
width:100%;
height:100%;
}
#iframe {
position: absolute;
float: left;
clear: both;
width: 100%;
height: 100%;
z-index: 0;
}
<div id="iframe"><iframe name="result" sandbox="allow-forms allow-popups allow-scripts allow-same-origin" frameborder="0" src="//fiddle.jshell.net/oleg_korol/a1bxr5ua/1/show/"></iframe></div>
WITHOUT IFRAME:
If you want to use the canvas as the background-image for the whole page, then the current code that you are using should work fine with width and height defined:
canvas {
position:absolute;
width:100%;
height:100%;
top:0px;
left:0px;
}
However if you want it as the background-image only for a certain div, then you can just add a position:relative; property to the parent div like this:
HTML:
<div id="canvas-box">
<canvas id=c></canvas>
</div>
CSS:
#canvas-box {
position:relative;
width:500px;
height:500px;
}
canvas {
position: absolute;
top: 0;
left: 0;
width:100%;
height:100%;
}
Here is a jsfiddle for adding canvas as background for a specific div: http://jsfiddle.net/AndrewL32/a1bxr5ua/5/

Related

When I render a small circle using JavaScript's getContext("2d"), it renders with a piece missing

I'm trying to make a very simple interactive segment for a webpage, and I need to render many small circles that bounce around the screen... However I am running into a very strange issue. When I render a small circle (with a radius of ~10 or less) it renders with a chunk taken out of the upper right corner for no apparent reason. If I increase the size of the circle then it begins to render properly.
Here is all of my code so far:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Nothing</title>
<style>
#header{
background: red;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 25%;
text-align: center;
}
#header h1{
position: relative;
top: 8%;
font-size: 200%;
}
#header canvas{
position: absolute;
left: 0;
top: 0;
}
</style>
</head>
<body>
<div id = "header">
<canvas></canvas>
<h1>(Removed for privacy)</h1>
</div>
<script>
let canvas = document.getElementById("header").getElementsByTagName("canvas")[0];
canvas.width = Math.round(window.innerWidth);
canvas.height = Math.round(window.innerHeight * 0.25);
let ctx = canvas.getContext("2d");
let width = canvas.width;
let height = canvas.height;
function d2r(degrees){
return(degrees * (Math.PI / 180));
}
function random(min,max){
const diff = (max - min) + 1;
return(Math.floor(Math.random() * diff) + min);
}
</script>
<script>
class Bubble{
constructor(x,y){
this.x = x;
this.y = y;
this.r = random(0,d2r(360));
this.speed = 0.6;
this.xvel = Math.cos(this.r) * this.speed;
this.yvel = Math.sin(this.r) * this.speed;
this.size = 10;
}
draw(){
ctx.beginPath();
ctx.fillStyle = "black";
ctx.arc(this.x,this.y,this.size / 2,this.size / 2,0,d2r(360));
ctx.fill();
}
update(){
this.x += this.xvel;
this.y += this.yvel;
if(this.x < this.size / 2){
this.x = this.size / 2;
this.xvel = -this.xvel;
}
if(this.x > width - this.size / 2){
this.x = width - this.size / 2;
this.xvel = -this.xvel;
}
if(this.y < this.size / 2){
this.y = this.size / 2;
this.yvel = -this.yvel;
}
if(this.y > height - this.size / 2){
this.y = height - this.size / 2;
this.yvel = -this.yvel;
}
}
}
let bubbles = [];
for(let i = 0;i < 50;i++){
bubbles.push(new Bubble(random(4,width - 4),random(4,height - 4)));
}
</script>
<script>
let drawLoop = setInterval(function(){
ctx.fillStyle = "rgb(84, 48, 23)";
ctx.fillRect(0,0,width,height);
for(let i = 0;i < bubbles.length;i++){
bubbles[i].update();
bubbles[i].draw();
}
},1000 / 60);
</script>
</body>
</html>
You can change the this.size = 10; to different sizes to see how it looks, and when the problem comes and goes. When I set it to something tiny (like 5) it renders as almost a line.... It's very very strange.
Any help is appreciated. I assume I'm going to have to use some kind of workaround to get this working the way I want.
Edit: The code in question is in the Bubble class, inside the draw method.
Parameters for 2dArc is
void ctx.arc(x, y, radius, startAngle, endAngle [, anticlockwise]);
Inside your class member draw() you gave,
ctx.arc(this.x,this.y,this.size / 2,this.size / 2,0,d2r(360));
Among which the second this.size / 2 is not required,
removing that will fix it,
ctx.arc(this.x,this.y,this.size / 2,0,d2r(360));

Change canvas size on an html page using javascript

The following question is based on an adaption I wish to make of this codepen:
Here is a Pen
I have the following html for displaying the canvas (I want it to be only in a section on the html page and not take up the whole page)
<div class="container">
<canvas id="c"></canvas>
</div>
The javascript for the canvas which shows an animation is below.
<script>
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
var H = window.innerHeight;
var W = window.innerWidth;
canvas.height = H;
canvas.width = W;
var NBR_PARTICLES = 100;
var INTENSITY = 55;
var BLUE_RATIO = 5;
particles = [];
for (var i = 0; i < NBR_PARTICLES; i++) {
particles.push( new particle(i) );
};
function particle(i){
this.size = rand(0, 1.4);
this.x = W / 2;
this.y = H / 2;
this.vx = rand(-1, 1);
this.vy = rand(-1, 1);
this.decay = rand(0.9, 1);
this.c = 0;
}
function draw(){
for (var i = 0; i < NBR_PARTICLES; i++) {
p = particles[i];
ctx.fillStyle = color(p.size);
ctx.beginPath();
ctx.arc(p.x, p.y, p.size, Math.PI*2, false);
ctx.fill();
p.size *= p.decay;
p.x += p.vx;
p.y += p.vy;
p.vx += rand(-.2, .2);
p.vy += rand(-.2, .2);
p.c++;
if(p.size < .2){
particles[i] = new particle(i);
}
};
}
function color(i){
value = 255 - Math.round( (i * (255 / NBR_PARTICLES)) * INTENSITY);
return "rgba(" + value + ", 0, " + Math.round((NBR_PARTICLES - i) / BLUE_RATIO) + ", .75)";
}
setInterval(draw, 33);
/*************************
CONSTRUCT FUNCTIONS
**************************/
function rand(min, max){
value = min + Math.random() * ( max - min );
return value;
}
function cd(args){ // FOR DEBUG
console.dir(args);
}
</script>
I want the canvas size to be a rectangular banner across the page rather than the whole page as it is now.
I have tried changing these variables
var H = window.innerHeight;
var W = window.innerWidth;
canvas.height = H;
canvas.width = W;
to
canvas.height = 200;
canvas.width = 800;
but that doesn't render the animation at all but does appear to resize the canvas.
The CSS here appears to override the existing body as the whole animation takes over the page and my existing content is no longer displayed.
body, html{
margin: 0;
padding: 0;
overflow: hidden;
background-color: #ddd;
}
I tried removing the body from the css but that didn't work at all.
I also, as you can see above, added a div container, hoping that would isolate the canvas but that hasn't worked either.
<div class="container">
<canvas id="c"></canvas>
</div>
How do I adapt this code to make the canvas only render on a portion (width and height of the canvas decided by me) on the screen.
Setting directly the height H and width W , will show canvas correctly at center :
below snippet you can see result centred annilation correctly
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
// set here canvas width and height directly
var H = 200;
var W = 200;
canvas.height = H;
canvas.width = W;
var NBR_PARTICLES = 100;
var INTENSITY = 55;
var BLUE_RATIO = 5;
particles = [];
for (var i = 0; i < NBR_PARTICLES; i++) {
particles.push( new particle(i) );
};
function particle(i){
this.size = rand(0, 1.4);
this.x = W / 2;
this.y = H / 2;
this.vx = rand(-1, 1);
this.vy = rand(-1, 1);
this.decay = rand(0.9, 1);
this.c = 0;
}
function draw(){
for (var i = 0; i < NBR_PARTICLES; i++) {
p = particles[i];
ctx.fillStyle = color(p.size);
ctx.beginPath();
ctx.arc(p.x, p.y, p.size, Math.PI*2, false);
ctx.fill();
p.size *= p.decay;
p.x += p.vx;
p.y += p.vy;
p.vx += rand(-.2, .2);
p.vy += rand(-.2, .2);
p.c++;
if(p.size < .2){
particles[i] = new particle(i);
}
};
}
function color(i){
value = 255 - Math.round( (i * (255 / NBR_PARTICLES)) * INTENSITY);
return "rgba(" + value + ", 0, " + Math.round((NBR_PARTICLES - i) / BLUE_RATIO) + ", .75)";
}
setInterval(draw, 33);
/*************************
CONSTRUCT FUNCTIONS
**************************/
function rand(min, max){
value = min + Math.random() * ( max - min );
return value;
}
function cd(args){ // FOR DEBUG
console.dir(args);
}
body, html{
margin: 0;
padding: 0;
overflow: hidden;
background-color: #ddd;
text-align:center
}
canvas {
border : 1px solid gray;
}
<canvas id="c"></canvas>

Pseudo element :after not displaying [duplicate]

This question already has an answer here:
Impossible to add pseudo element to canvases?
(1 answer)
Closed 3 years ago.
As you can see I wan to have a line running through the center of my canvas, so I have decided to use the after element! It is rendering, as can bee seen in the screenshot of the console, but for whatever reason it eill not display! I am at a loss of what I am doing wrong! Thank you! Here is my Code Pen
The code:
function start() {
var canvas = $("canvas");
console.log(canvas);
canvas.each(function(index, canvas) {
var context = canvas.getContext("2d");
canvas.width = $(".box").eq(index).width();
canvas.height = $(".box").eq(index).height();
context.clearRect(0, 0, canvas.width, canvas.height);
drawCurves(context, step);
step += 1;
});
requestAnimationFrame(start);
}
var step = -1;
function drawCurves(ctx, step) {
var width = ctx.canvas.width;
var height = ctx.canvas.height;
ctx.lineWidth = 2;
for (i = 0; i < 4 ; i++) {
var x = 0;
var y = 0;
ctx.beginPath();
if (i === 0 ) {
ctx.strokeStyle = "red";
var amplitude = 20;
var frequency = height / (2 * Math.PI);
console.log(i, frequency);
ctx.save();
ctx.translate(-amplitude * Math.sin(step / frequency), 0);
} if ( i === 1) {
ctx.strokeStyle = "blue";
var amplitude = 30;
var frequency = (height / (2 * Math.PI));
console.log(i, frequency);
ctx.save();
ctx.translate(-amplitude * Math.sin(step / frequency), 0);
} if ( i === 2) {
ctx.strokeStyle = "green";
var amplitude = 40;
var frequency = height / (2 * Math.PI) ;
console.log(i, frequency);
ctx.save();
ctx.translate(-amplitude * Math.sin(step / frequency), 0);
} if (i === 3) {
ctx.strokeStyle = "yellow";
var amplitude = 50;
var frequency = height / (2 * Math.PI) ;
console.log(i, frequency);
ctx.save();
ctx.translate(-amplitude * Math.sin(step / frequency), 0);
}
while (y < height ) {
x = (width / 2) + (amplitude * Math.sin((y + step) / frequency)) ;
ctx.lineTo(x, y);
y++;
}
ctx.stroke();
ctx.restore();
}
}
$(document).ready(function() {
start();
})
canvas {
background-color: wheat;
position: absolute;
&:after {
content: '';
display: block;
position: absolute;
background-color: #EA777A;
width: 20px;
height: 100%;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
}
.box {
width: 500px;
height: 2000px;
border: solid;
}
.box.t {
width: 500px;
height: 200px;
border: solid;
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div class="box t">
<canvas id="canvas"></canvas>
</div>
<div class="box">
<canvas id="canvas"></canvas>
</div>
</body>
</html>
Screenshot of the rendered code:
Canvas can't have an ::after. You can wrap it in a <div> and give that an ::after though.

HTML h1 tag not displaying correctly above javascript+css animation

I have the following code (from a code pen fork), and wish to add a simple Html H1 tag above the animation on the page. I have tried the below, but for some reason the H1 tag just displays for a second (flashes) and then disappears off the screen.
I have tried placing it in several places and also used tags, but the same thing happens.
Can someone please suggest a fix and also explain why this is occuring?
html, javascript file: and CSS File (style.css)
class Canvas {
constructor(element, ctx, w, h) {
this.element = element
this.ctx = ctx
this.width = w
this.height = h
this.interactive = false
this.playing = true
this.point = {
value: 150,
speed: 0.25,
limit: 70,
floor: 10,
up: true,
animating: false
}
this.multiplier = {
value: 1,
speed: 0.005,
limit: 20,
floor: 1,
up: true,
animating: true
}
this.center = {
x: w / 2,
y: h / 2,
targetX: w / 2,
targetY: h / 2,
easing: 0.02
}
this.radius = {
val: h / 2.2,
targetVal: h / 2.2,
easing: 0.02
}
document.body.addEventListener('click', this.click.bind(this))
document.body.addEventListener('mousemove', this.move.bind(this))
document.body.addEventListener('keyup', this.keyup.bind(this))
this.hue = 160
}
click(e) {
this.interactive = !this.interactive
if (!this.interactive) {
this.center.targetX = this.width / 2
this.center.targetY = this.height / 2
this.radius.targetVal = this.height / 2.2
this.element.classList.remove('interactive')
} else {
this.element.classList.add('interactive')
}
}
move(e) {
if (!this.interactive) {
return
}
const h3 = this.height / 3
this.center.targetX = e.pageX
this.center.targetY = Math.max(e.pageY, h3)
this.radius.targetVal = h3 + (e.pageY * 0.8)
}
keyup(e) {
if (e.which != 32) {
return
}
this.playing = !this.playing
if (this.playing && this.drawLoop) {
this.drawLoop()
}
}
update() {
this.clear()
this.animate(this.point)
this.animate(this.multiplier)
this.ease(this.center)
this.ease(this.radius)
this.hue += 0.3
const h = (this.hue % 360)
this.ctx.fillStyle = 'hsl(' + h + ',70%,20%)'
this.ctx.strokeStyle = 'hsla(' + h + ',80%,60%,0.2)'
this.ctx.globalCompositeOperation = 'lighter'
}
clear() {
this.ctx.globalCompositeOperation = 'source-over'
this.ctx.fillStyle = 'rgba(0,0,0,0.1)'
this.ctx.rect(0, 0, this.width, this.height)
this.ctx.fill()
}
draw() {
let radius = this.radius.val
const w2 = this.center.x,
h2 = this.center.y
this.ctx.beginPath()
this.ctx.shadowBlur = 0
this.ctx.shadowColor = 'black'
const points = this.point.value
const multiplier = this.multiplier.value
for (let p = 0; p < points; p++) {
const t = (p / points) * Math.PI * 2
const t2 = ((p * multiplier) / points) * Math.PI * 2
const x = radius * Math.cos(t) + w2
const y = radius * Math.sin(t) + h2
const x2 = radius * Math.cos(t2) + w2
const y2 = radius * Math.sin(t2) + h2
this.ctx.moveTo(x, y)
this.ctx.lineTo(x2, y2)
}
this.ctx.arc(w2, h2, radius, 0, 2 * Math.PI)
this.ctx.stroke()
this.ctx.closePath()
}
animate(object) {
if (!object.animating) {
return
}
if (object.up) {
object.value += object.speed
} else {
object.value -= object.speed
}
if (object.value > object.limit) {
object.up = false
} else if (object.value < object.floor) {
object.up = true
}
}
ease(object) {
if (object.val) {
const dv = object.targetVal - object.val
object.val += dv * object.easing
return
}
const dx = object.targetX - object.x
const dy = object.targetY - object.y
object.x += dx * object.easing
object.y += dy * object.easing
}
random(from, to) {
return from + (Math.rand() * (to - from))
}
resize(w, h) {
this.width = w
this.height = h
this.center.targetX = w / 2
this.center.targetY = h / 2
this.radius.targetVal = h / 2.2
}
}
(_ => {
const canvasElement = document.getElementById('canvas'),
ctx = canvasElement.getContext('2d')
let w = canvasElement.width = window.innerWidth,
h = canvasElement.height = window.innerHeight,
density = 1
const canvas = new Canvas(canvasElement, ctx, w, h)
function setup() {
window.addEventListener('resize', resize)
density = window.devicePixelRatio != undefined ? window.devicePixelRatio : 1.0
canvasElement.width = w * density
canvasElement.height = h * density
canvas.width = w
canvas.height = h
canvas.drawLoop = draw
ctx.scale(density, density)
draw()
}
function draw() {
canvas.update()
canvas.draw()
if (canvas.playing) {
window.requestAnimationFrame(draw)
}
}
function resize() {
w = canvasElement.width = window.innerWidth
h = canvasElement.height = window.innerHeight
canvasElement.width = w * density
canvasElement.height = h * density
canvas.resize(w, h)
ctx.scale(density, density)
}
setup()
})()
body {
background: #000;
overflow: hidden;
}
canvas {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
}
canvas.interactive {
cursor: none;
}
<html>
<head>
<link rel="stylesheet" href="style.css">
<center>
<h1>
<font color="white">This is the H1 Tag</font>
</h1>
</center>
</head>
<body>
<br>
<br>
<br>
<br>
<canvas id="canvas"></canvas>
Update
Thanks to the answer below, I have changed the css to the following, and the tag does display, but the animation is not centered. How can the canvas be re-positioned so that other 'elements' or objects can be fit around it?
canvas {
width: 30%;
height: 30%;
position: absolute;
left: 0;
top: 0;
}
This is because your canvas style is set to take up the whole page. Your h1 is also inside the head of the document. So that needs moved into the body too.
canvas {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
}
If you remove the canvas style, your h1 will sit above the canvas.
Edit:
Reading between the lines OP wants the image scaled down and centered. I've created a Fiddle to show how this can be achieved.
Fiddle
Add some z-index to your h1 and remove the obsolete tags:
class Canvas {
constructor(element, ctx, w, h) {
this.element = element
this.ctx = ctx
this.width = w
this.height = h
this.interactive = false
this.playing = true
this.point = {
value: 150,
speed: 0.25,
limit: 70,
floor: 10,
up: true,
animating: false
}
this.multiplier = {
value: 1,
speed: 0.005,
limit: 20,
floor: 1,
up: true,
animating: true
}
this.center = {
x: w / 2,
y: h / 2,
targetX: w / 2,
targetY: h / 2,
easing: 0.02
}
this.radius = {
val: h / 2.2,
targetVal: h / 2.2,
easing: 0.02
}
document.body.addEventListener('click', this.click.bind(this))
document.body.addEventListener('mousemove', this.move.bind(this))
document.body.addEventListener('keyup', this.keyup.bind(this))
this.hue = 160
}
click(e) {
this.interactive = !this.interactive
if (!this.interactive) {
this.center.targetX = this.width / 2
this.center.targetY = this.height / 2
this.radius.targetVal = this.height / 2.2
this.element.classList.remove('interactive')
} else {
this.element.classList.add('interactive')
}
}
move(e) {
if (!this.interactive) {
return
}
const h3 = this.height / 3
this.center.targetX = e.pageX
this.center.targetY = Math.max(e.pageY, h3)
this.radius.targetVal = h3 + (e.pageY * 0.8)
}
keyup(e) {
if (e.which != 32) {
return
}
this.playing = !this.playing
if (this.playing && this.drawLoop) {
this.drawLoop()
}
}
update() {
this.clear()
this.animate(this.point)
this.animate(this.multiplier)
this.ease(this.center)
this.ease(this.radius)
this.hue += 0.3
const h = (this.hue % 360)
this.ctx.fillStyle = 'hsl(' + h + ',70%,20%)'
this.ctx.strokeStyle = 'hsla(' + h + ',80%,60%,0.2)'
this.ctx.globalCompositeOperation = 'lighter'
}
clear() {
this.ctx.globalCompositeOperation = 'source-over'
this.ctx.fillStyle = 'rgba(0,0,0,0.1)'
this.ctx.rect(0, 0, this.width, this.height)
this.ctx.fill()
}
draw() {
let radius = this.radius.val
const w2 = this.center.x,
h2 = this.center.y
this.ctx.beginPath()
this.ctx.shadowBlur = 0
this.ctx.shadowColor = 'black'
const points = this.point.value
const multiplier = this.multiplier.value
for (let p = 0; p < points; p++) {
const t = (p / points) * Math.PI * 2
const t2 = ((p * multiplier) / points) * Math.PI * 2
const x = radius * Math.cos(t) + w2
const y = radius * Math.sin(t) + h2
const x2 = radius * Math.cos(t2) + w2
const y2 = radius * Math.sin(t2) + h2
this.ctx.moveTo(x, y)
this.ctx.lineTo(x2, y2)
}
this.ctx.arc(w2, h2, radius, 0, 2 * Math.PI)
this.ctx.stroke()
this.ctx.closePath()
}
animate(object) {
if (!object.animating) {
return
}
if (object.up) {
object.value += object.speed
} else {
object.value -= object.speed
}
if (object.value > object.limit) {
object.up = false
} else if (object.value < object.floor) {
object.up = true
}
}
ease(object) {
if (object.val) {
const dv = object.targetVal - object.val
object.val += dv * object.easing
return
}
const dx = object.targetX - object.x
const dy = object.targetY - object.y
object.x += dx * object.easing
object.y += dy * object.easing
}
random(from, to) {
return from + (Math.rand() * (to - from))
}
resize(w, h) {
this.width = w
this.height = h
this.center.targetX = w / 2
this.center.targetY = h / 2
this.radius.targetVal = h / 2.2
}
}
(_ => {
const canvasElement = document.getElementById('canvas'),
ctx = canvasElement.getContext('2d')
let w = canvasElement.width = window.innerWidth,
h = canvasElement.height = window.innerHeight,
density = 1
const canvas = new Canvas(canvasElement, ctx, w, h)
function setup() {
window.addEventListener('resize', resize)
density = window.devicePixelRatio != undefined ? window.devicePixelRatio : 1.0
canvasElement.width = w * density
canvasElement.height = h * density
canvas.width = w
canvas.height = h
canvas.drawLoop = draw
ctx.scale(density, density)
draw()
}
function draw() {
canvas.update()
canvas.draw()
if (canvas.playing) {
window.requestAnimationFrame(draw)
}
}
function resize() {
w = canvasElement.width = window.innerWidth
h = canvasElement.height = window.innerHeight
canvasElement.width = w * density
canvasElement.height = h * density
canvas.resize(w, h)
ctx.scale(density, density)
}
setup()
})()
body {
background: #000;
overflow: hidden;
}
h1 {
position:relative;
z-index:2;
color:#fff;
text-align:center;
}
canvas {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
}
canvas.interactive {
cursor: none;
}
<canvas id="canvas"></canvas>
<h1>This is a title</h1>
This is because of your canvas styles. If you add a margin-top to your canvas the h1 will not be removed, try it like this:
canvas {
margin-top: 200px;
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
}
You'll see that now your h1 is not dissapearing anymore.
Edit
Reading between the lines OP appears to want it scaled down and centered, so I've created a fiddle with updated code.
Fiddle

How to fix cloud rising?

I have a cloud image which is supposed to rise while user scrolling down but it's being clipped at the bottom and, therefore, looks ugly. The image itself is good. It seems to me that I have to change CSS in some way. How can I fix that?
Here's Codepen sandbox.
HTML
<canvas id="canvas"></canvas>
<div class="front" id="front">
<div class="cloud">
<div class="scroll-arrows">
SCROLL TO MOVE THE CLOUD
</div>
</div>
</div>
CSS
body {
height: 1000vh;
margin: 0;
}
canvas {
width: 100%;
height: 100vh;
position: fixed;
}
.front {
text-align: center;
background: url("https://res.cloudinary.com/active-bridge/image/upload/v1448008261/cloud.png") no-repeat 50% 50%/cover;
pointer-events: none;
position: absolute;
top: 0;
left: 0;
right: 0;
font-size: 14px;
z-index: 1;
line-height: 100vh;
}
.front .cloud {
display: inline-block;
width: 40%;
line-height: 1;
vertical-align: middle;
}
JS
front = document.getElementById('front');
var timeOut;
window.onresize = function() {
if(timeOut)
clearTimeout(timeOut);
timeOut = setTimeout(draw, 10);
}
window.onload = draw;
window.onscroll = navigate;
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
forest = new Image;
forest.src = 'http://p1.pichost.me/i/33/1561150.jpg';
function navigate() { draw() }
function draw(scroll) {
scroll = (window.scrollY || window.pageYOffset) / (document.body.clientHeight - window.innerHeight) * 3000;
canvas.setAttribute('width', window.innerWidth);
canvas.setAttribute('height', window.innerHeight);
drawImageProp(ctx, forest, 0, (-scroll*3.9)/4, canvas.width, canvas.height + (scroll*3.9)/2);
}
function drawImageProp(ctx, img, x, y, w, h, offsetX, offsetY) {
if (arguments.length === 2) {
x = y = 0;
w = ctx.canvas.width;
h = ctx.canvas.height;
}
// default offset is center
offsetX = typeof offsetX === "number" ? offsetX : 0.5;
offsetY = typeof offsetY === "number" ? offsetY : 0.5;
// keep bounds [0.0, 1.0]
if (offsetX < 0) offsetX = 0;
if (offsetY < 0) offsetY = 0;
if (offsetX > 1) offsetX = 1;
if (offsetY > 1) offsetY = 1;
var iw = img.width,
ih = img.height,
r = Math.min(w / iw, h / ih),
nw = iw * r, // new prop. width
nh = ih * r, // new prop. height
cx, cy, cw, ch, ar = 1;
// decide which gap to fill
if (nw < w) ar = w / nw;
if (nh < h) ar = h / nh;
nw *= ar;
nh *= ar;
// calc source rectangle
cw = iw / (nw / w);
ch = ih / (nh / h);
cx = (iw - cw) * offsetX;
cy = (ih - ch) * offsetY;
// make sure source rectangle is valid
if (cx < 0) cx = 0;
if (cy < 0) cy = 0;
if (cw > iw) cw = iw;
if (ch > ih) ch = ih;
// fill image in dest. rectangle
ctx.drawImage(img, cx, cy, cw, ch, x, y, w, h);
}
Giving the .front div a set height fixes the problem insted of it being position:absolute
Code
.front {
text-align: center;
background: url("https://res.cloudinary.com/active-bridge/image/upload/v1448008261/cloud.png") no-repeat 50% 50%/cover;
pointer-events: none;
height: 850px;
position: relative;
font-size: 14px;
z-index: 1;
line-height: 100vh;
}
Example

Categories

Resources