Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URLs added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Auto Save

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <svg>
<g id="grid" stroke="lightgrey" transform="scale(0.3)">
  <line x1="0" y1="1250" x2="9000" y2="1250" style="stroke-dasharray:1,48,1,0;stroke-width:9000;"/>
  <line x1="2000" y1="0" x2="2000" y2="9000" style="stroke-dasharray:1,48,1,0;stroke-width:9000;"/>
</g>
</svg>
<canvas id="myCanvas"> </canvas>

              
            
!

CSS

              
                body {
  font: 15px arial, sans-serif;
  background-color: white;
  overflow:hidden;
  cursor: crosshair;
}

h2 {
  font: 25px arial, sans-serif;
}
canvas {
  position: absolute;
  left: 0;
  top: 0;
  z-index: -1;
}
svg{
  position: absolute;
  left: 0;
  top: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
}

              
            
!

JS

              
                // todo
window.onresize = function(event) {
  ctx.canvas.width = window.innerWidth;
  ctx.canvas.height = window.innerHeight;
  ctx.shadowBlur = 30;
  ctx.shadowOffsetY = 30;
  ctx.shadowOffsetX = 10;
  if (physics.lines) {
    ctx.shadowColor = physics.color;
  } else {
    ctx.shadowColor = "transparent";
  }
  ctx.lineWidth = physics.drawSize;
};
var physics = {
  cycle: 0, //keeps track of cycle
  pause: false, // pauses the simulation
  speed: 6, //speed of waves and max speed of source
  totalNodes: Math.round(window.innerWidth / 4), //spawns stars at start
  control: "sine wave", //input mode  (keys 1,2,3,4 switch)
  period: 10 * Math.PI / 30,
  amplitude: 30,
  info: false, //toggles info display for sinewave:  press "i"
  lines: true, //toggles lines or squares:  press "l"
  multiwave: false,
  drawSize: 3, //changes length of squares for each rectangle node
  color: "#000000",
  alpha: 1,
  time: false,
  xOffset: 0, //0.5 * window.innerWidth,
  yOffset: 0.5 * window.innerHeight,
};

/* var pausefunction = function() {
  this.pauseToggle = function() {
    if (physics.pause) {
      physics.pause = false;
    } else {
      physics.pause = true;
    }
  };
}; */

// draw the graphical user interface form the dat.GUI library
var gui = new dat.GUI();
gui.close();
gui.add(physics, 'pause');
gui.add(physics, 'speed', 0, 50);
var controlController = gui.add(physics, 'control', ['mouse:raw', 'mouse:speed cap', 'sine wave', 'circle', 'super position 1', 'super position 2', 'super position 3', 'longitudinal wave']);
controlController.onChange(function(value) {
  if (value === 'mouse:raw' || value === 'mouse:speed cap') {
    sineFolder.close();
  } else {
    sineFolder.open();
  }
});

var sineFolder = gui.addFolder('sine controls');
sineFolder.add(physics, 'info');
sineFolder.add(physics, 'amplitude', 0, window.innerHeight / 2);
sineFolder.add(physics, 'period', 0, 5);
sineFolder.open();
var looksFolder = gui.addFolder('looks');
looksFolder.add(physics, 'time');
var linesController = looksFolder.add(physics, 'lines');
linesController.onChange(function(value) {
  if (physics.lines) ctx.shadowColor = physics.color;
  else ctx.shadowColor = "transparent";
});
//looksFolder.add(physics, 'multiwave');
var drawSizeController = looksFolder.add(physics, 'drawSize', 1, 50);
drawSizeController.onChange(function(value) {
  ctx.lineWidth = physics.drawSize;
});
var alphaController = looksFolder.add(physics, 'alpha', 0, 1);
alphaController.onChange(function(value) {
  ctx.globalAlpha = value;
});
var colorController = looksFolder.addColor(physics, 'color');
colorController.onChange(function(value) {
  ctx.fillStyle = value;
  ctx.strokeStyle = value;
  if (physics.lines) ctx.shadowColor = value;
  else ctx.shadowColor = "transparent";
});

var drawPos = {
  x: physics.xOffset,
  y: physics.yOffset,
};

var fontSize = 20;
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
//ctx.globalCompositeOperation = 'source-over';
ctx.globalAlpha = 1;
ctx.textAlign = "center";
ctx.fillStyle = "#000000";
ctx.strokeStyle = "#000000";
ctx.lineWidth = physics.drawSize;
ctx.lineJoin = 'round'; //miter, round
ctx.lineCap = "round";
ctx.shadowBlur = 30;
ctx.shadowOffsetY = 30;
ctx.shadowOffsetX = 10;
if (physics.lines) ctx.shadowColor = "black";
else ctx.shadowColor = "transparent";

var mousePos = {
  x: window.innerWidth * 0.5,
  y: window.innerHeight * 0.5
};

//gets mouse position
function getMousePos(canvas, evt) {
  var rect = canvas.getBoundingClientRect();
  return {
    x: evt.clientX - rect.left,
    y: evt.clientY - rect.top
  };
}
// waits for mouse move and then updates position
canvas.addEventListener('mousemove', function(evt) {
  mousePos = getMousePos(canvas, evt);
}, false);

canvas.addEventListener("mousedown", function() {
  physics.xOffset = mousePos.x
  physics.yOffset = mousePos.y
});

function controlMode() {
  switch (physics.control) {
    case "mouse:speed cap":
      smoothMouseWave();
      break;
    case "mouse:raw":
      mouseWave();
      break;
    case "sine wave":
      sineWave(0, physics.amplitude, physics.period); //sine wave  (X amp, Y amp, period)
      break;
    case "circle":
      sineWave(physics.amplitude, physics.amplitude, physics.period); //circle
      break;
    case "super position 1":
      sineWaves(0, physics.amplitude, physics.period, 0, physics.amplitude, physics.period * 0.85); // 2 sine waves slightly out of sync
      break;
    case "super position 2":
      sineWaves(0, physics.amplitude, physics.period, 0, physics.amplitude / 10, physics.period / 10); // 2 sine waves: one big and one small
      break;
    case "super position 3":
      sineWaves(physics.amplitude, physics.amplitude, physics.period, 0, physics.amplitude, physics.period * 0.85); //
      break;
    case "longitudinal wave":
      sineWave(physics.amplitude, 0, physics.period); // wave that moves like sound
      break;
    default:
      mouseWave();
  }
}

function smoothMouseWave() {
  //gravitate towards mouse
  var dir = Math.atan2(drawPos.y - mousePos.y, drawPos.x - mousePos.x)
  var dist = Math.sqrt((drawPos.x - mousePos.x) * (drawPos.x - mousePos.x) + (drawPos.y - mousePos.y) * (drawPos.y - mousePos.y));
  if (dist > 5) {
    var speed = 0;
    if ((dist) < 200) {
      speed = dist / 200 * physics.speed;
    } else {
      speed = physics.speed * 0.99;
    }
    drawPos.x -= speed * Math.cos(dir);
    drawPos.y -= speed * Math.sin(dir);
  }
}

function mouseWave() {
  drawPos.x = mousePos.x;
  drawPos.y = mousePos.y;
}

function sineWave(ampX, ampY, T) {
  waveProperties(T, ampY);
  T = T * 30 / Math.PI
  drawPos.x = ampX * Math.cos(physics.cycle / T) + physics.xOffset;
  drawPos.y = ampY * Math.sin(physics.cycle / T) + physics.yOffset;
}

function sineWaves(ampX, ampY, T, ampX2, ampY2, T2) {
  waveProperties(T, ampY);
  T = T * 30 / Math.PI
  T2 = T2 * 30 / Math.PI
  drawPos.x = ampX * Math.cos(physics.cycle / T) + physics.xOffset;
  drawPos.x += ampX2 * Math.cos(physics.cycle / T2);
  drawPos.y = ampY * Math.sin(physics.cycle / T) + physics.yOffset;
  drawPos.y += ampY2 * Math.sin(physics.cycle / T2);
}

function waveProperties(T, ampY) {
  if (physics.info) {
    ctx.font = fontSize + "px Arial";
    ctx.textAlign = "start";
    ctx.fillText("y = " + ampY.toFixed(5).substring(0, 5) + " sin(" + (1 / T).toFixed(5).substring(0, 5) + " x)", 5, fontSize + 10);
    ctx.fillText("f = " + (1 / T).toFixed(5).substring(0, 5) + "Hz", 5, fontSize + 40);
    ctx.fillText("T = " + (T).toFixed(5).substring(0, 5) + "s", 5, fontSize + 70);
    ctx.fillText("λ = " + (physics.speed * 60 * T).toFixed(5).substring(0, 5) + "px", 5, fontSize + 100);
    ctx.fillText("v = " + (physics.speed * 60).toFixed(5).substring(0, 5) + "px/s", 5, fontSize + 130);
    ctx.fillText("A = " + ampY.toFixed(5).substring(0, 5) + " px", 5, fontSize + 160);
    // center line
    ctx.beginPath();
    ctx.moveTo(0, physics.yOffset);
    ctx.lineTo(window.innerWidth, physics.yOffset);
    ctx.stroke();
  }
}

function time() {
  if (physics.time) {
    var d = new Date();
    var hour = d.getHours();
    var min = d.getMinutes();
    var sec = d.getSeconds();
    var ms = d.getMilliseconds().toFixed(2).substring(0, 2);
    ctx.textAlign = "end";
    ctx.font = fontSize + "px Monospace";
    ctx.fillText(hour + 'h:' + min + 'm:' + sec + "." + ms + 's', window.innerWidth, window.innerHeight - 13);
  }
}

/* window.onresize = function(event) {
  ctx.canvas.width = window.innerWidth;
  ctx.canvas.height = window.innerHeight;
  container.height = window.innerHeight;
  container.width = window.innerWidth;
}; */

var node1 = [],
  node2 = [],
  node3 = [],
  node4 = [],
  node5 = [],
  node6 = [],
  node7 = [],
  node8 = [],
  node9 = [],
  node10 = [],
  node11 = [],
  node12 = [],
  node13 = [],
  node14 = [],
  node15 = [],
  node16 = [];

//adds a new star objects to array stars
function pushNode(i, dirX, dirY, node) {
  node.push({
    x: drawPos.x,
    y: drawPos.y,
    Vx: dirX,
    Vy: dirY,
    returnCycle: i,
  });
}
//spawns stars at the start in 8 different directions
for (var i = 0; i < physics.totalNodes; i++) {
  pushNode(i, 1, 0, node1);
  pushNode(i, -1, 0, node2);
  pushNode(i, 0, 1, node3);
  pushNode(i, 0, -1, node4);
  pushNode(i, 0.7, 0.7, node5);
  pushNode(i, -0.7, -0.7, node6);
  pushNode(i, 0.7, -0.7, node7);
  pushNode(i, -0.7, 0.7, node8);
  pushNode(i, 0.92, 0.38, node9);
  pushNode(i, -0.92, 0.38, node10);
  pushNode(i, 0.92, -0.38, node11);
  pushNode(i, -0.92, -0.38, node12);
  pushNode(i, 0.38, 0.92, node13);
  pushNode(i, -0.38, 0.92, node14);
  pushNode(i, 0.38, -0.92, node15);
  pushNode(i, -0.38, -0.92, node16);
}

function fieldLineLoop(node) { //lines
  ctx.beginPath();
  i = node.length;
  ctx.moveTo(node[i - 1].x, node[i - 1].y);
  while (i--) {
    ctx.lineTo(node[i].x, node[i].y);
    //move node
    node[i].x += node[i].Vx * physics.speed;
    node[i].y += node[i].Vy * physics.speed;
    //check for return
    if (node[i].returnCycle < physics.cycle) {
      node.splice(i, 1);
      pushNode(physics.cycle + physics.totalNodes - 1, node[i].Vx, node[i].Vy, node);
    }
  }
  ctx.stroke();
}

function fieldDotLoop(node) { //turn shadows off for this
  i = node.length;
  while (i--) {
    /*ctx.beginPath();    //cirlces are slower then rectangles
      ctx.arc(node[i].x, node[i].y, physics.drawSize, 0, 2 * Math.PI);
      ctx.fill(); */
    //ctx.fillStyle='#' + Math.floor(Math.random() * 16777216).toString(16);
    ctx.fillRect(node[i].x, node[i].y, physics.drawSize, physics.drawSize);
    //move node
    node[i].x += node[i].Vx * physics.speed;
    node[i].y += node[i].Vy * physics.speed;
    //check for return
    if (node[i].returnCycle < physics.cycle) {
      node.splice(i, 1);
      pushNode(physics.cycle + physics.totalNodes - 1, node[i].Vx, node[i].Vy, node);
    }
  }
}

function draw() {
  if (physics.pause === false) {
    physics.cycle++;
    ctx.clearRect(0, 0, window.innerWidth, window.innerHeight);
    time();
    controlMode();

    //draw each line
    if (physics.lines) {
      fieldLineLoop(node1);
      if (physics.multiwave) {
        fieldLineLoop(node2);
        fieldLineLoop(node3);
        fieldLineLoop(node4);
        fieldLineLoop(node5);
        fieldLineLoop(node6);
        fieldLineLoop(node7);
        fieldLineLoop(node8);
        fieldLineLoop(node9);
        fieldLineLoop(node10);
        fieldLineLoop(node11);
        fieldLineLoop(node12);
        fieldLineLoop(node13);
        fieldLineLoop(node14);
        fieldLineLoop(node15);
        fieldLineLoop(node16);
      }
    } else {
      fieldDotLoop(node1);
      if (physics.multiwave) {
        fieldDotLoop(node2);
        fieldDotLoop(node3);
        fieldDotLoop(node4);
        fieldDotLoop(node5);
        fieldDotLoop(node6);
        fieldDotLoop(node7);
        fieldDotLoop(node8);
        fieldDotLoop(node9);
        fieldDotLoop(node10);
        fieldDotLoop(node11);
        fieldDotLoop(node12);
        fieldDotLoop(node13);
        fieldDotLoop(node14);
        fieldDotLoop(node15);
        fieldDotLoop(node16);
      }
    }
  }
  requestAnimationFrame(draw);
}
requestAnimationFrame(draw);
              
            
!
999px

Console