Fixing Ocean at night in Canvas

Issue

So I have wanted to make an ocean in the night with a canvas. I got the Wave part down but I want them to be filled. So that they are not just a lign anymore but a solid block locking like waves. I really like how they look right now but if you have any tweeks that could make them look even better feel free to share them!
Thanks for the Help in Advance!

var c = document.getElementById("screen2");
var ctx = c.getContext("2d");
var cw = c.width = window.innerWidth;
var ch = c.height = window.innerHeight;
var cx = cw / 2,
  cy = ch / 2;
var rad = Math.PI / 180;
var w = window.innerWidth;
var h = 100;
var amplitude = h;
var frequency = .01;
var phi = 0;
var frames = 0;
var stopped = true;
//ctx.strokeStyle = "Cornsilk";
ctx.lineWidth = 4;
//first wave
function Draw() {
  frames++
  phi = frames / 88;
  ctx.clearRect(0, 0, cw, ch);
  ctx.beginPath();
 
  ctx.moveTo(0, ch);
  for (var x = 0; x < w; x++) {
    y = Math.sin(x * frequency + phi) * amplitude/2 + amplitude /2;
    //y = Math.cos(x * frequency + phi) * amplitude / 2 + amplitude / 2;
    ctx.lineTo(x, y + ch -110); // setting it to the bottom of the page 100= lift

  }
  ctx.lineTo(w, ch);
  ctx.lineTo(0, ch);
  ctx.stroke();
  requestId = window.requestAnimationFrame(Draw);
}
requestId = window.requestAnimationFrame(Draw);

//second wave
function Draw2() {
  frames++
  phi = frames / 72 ;
  
  ctx.beginPath();
 
  ctx.moveTo(0, ch);
  for (var x = 0; x < w; x++) {
    y = Math.sin(x * frequency + phi) * amplitude/4  + amplitude/4;
    //y = Math.cos(x * frequency + phi) * amplitude / 2 + amplitude / 2;
    ctx.lineTo(x, y + ch -110); // setting it to the bottom of the page 100= lift

  }
  ctx.lineTo(w, ch);
  ctx.lineTo(0, ch);
  ctx.stroke();
  requestId = window.requestAnimationFrame(Draw2);
}
requestId = window.requestAnimationFrame(Draw2);
canvas {
        display:block; 
        margin:0 auto;
        width:100%; 
        height:100vh;
        }
<canvas id="screen2"></canvas>

Solution

First and foremost what I really would change is using requestAnimationFrame two times as it’s completely redundant. You can group your drawing operations in a single function and just execute this.

As @mousetail hinted a simple ‘fix’ would be using .fill() instead of .stroke(). The problem is that you would have two completely solid shapes of the same colour making it look like there’s just a single wave. So the next step would be adding two different colours. As that might still look a little boring I’d use two linear gradients – a lighter for the foreground and a darker for the background wave.

To make it look even more interesting I’d move the waves up & down over time.

var c = document.getElementById("screen2");
var ctx = c.getContext("2d");
var cw = c.width = window.innerWidth;
var ch = c.height = window.innerHeight;
var cx = cw / 2,
  cy = ch / 2;
var rad = Math.PI / 180;
var w = window.innerWidth;
var h = 100;
var amplitude = h;
var frequency = .01;
var phi = 0;
var frames = 0;
var stopped = true;

var gradientA = ctx.createLinearGradient(0, ch / 2, 0, ch);
gradientA.addColorStop(0, "#29c3d3");
gradientA.addColorStop(1, "#15656e");

var gradientB = ctx.createLinearGradient(0, ch / 2, 0, ch);
gradientB.addColorStop(0, "#55dee5");
gradientB.addColorStop(1, "#399499");

ctx.lineWidth = 4;
var step = 0;

function drawWaves() {
  frames++;
  phi = frames / 88;
  ctx.clearRect(0, 0, cw, ch);
  ctx.beginPath();
  ctx.moveTo(0, ch);
  for (var x = 0; x < w; x++) {
    y = Math.sin(x * frequency + phi) * amplitude / 2 + amplitude / 2;
    //y = Math.cos(x * frequency + phi) * amplitude / 2 + amplitude / 2;
    ctx.lineTo(x, y + ch - 110 + Math.sin(step / 2) * 10); // setting it to the bottom of the page 100= lift

  }
  ctx.lineTo(w, ch);
  ctx.lineTo(0, ch);
  ctx.fillStyle = gradientA;
  ctx.fill();
  frames++;
  phi = frames / 72;

  ctx.beginPath();

  ctx.moveTo(0, ch);
  for (var x = 0; x < w; x++) {
    y = Math.sin(x * frequency + phi) * amplitude / 4 + amplitude / 4;
    //y = Math.cos(x * frequency + phi) * amplitude / 2 + amplitude / 2;
    ctx.lineTo(x, y + ch - 110 + Math.sin(step) * 20); // setting it to the bottom of the page 100= lift

  }
  ctx.lineTo(w, ch);
  ctx.lineTo(0, ch);
  ctx.fillStyle = gradientB;
  ctx.fill();
  step += 0.02;
  requestId = window.requestAnimationFrame(drawWaves);
}

requestId = window.requestAnimationFrame(drawWaves);
canvas {
  display: block;
  margin: 0 auto;
  width: 100%;
  height: 100vh;
}
<canvas id="screen2"></canvas>

Answered By – obscure

Answer Checked By – Mildred Charles (AngularFixing Admin)

Leave a Reply

Your email address will not be published.