canvas实现彩色立体波浪形背景效果代码

代码语言:html

所属分类:背景

代码描述:canvas实现彩色立体波浪形背景效果代码,点击可切换。

代码标签: canvas 彩色 立体 波浪形 背景

下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开

<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">
  

  
  
<style>
body {
  font-family: Arial, Helvetica, "Liberation Sans", FreeSans, sans-serif;
  background-color: #000;
  margin: 0;
  padding: 0;
  border-width: 0;
  overflow: hidden;
}
</style>

  
  
</head>

<body translate="no">
  
  
      <script  >
"use strict";

let canv, ctx; // canvas and context
let maxx, maxy; // canvas dimensions

let radius; // hexagons radius (and side length)
let grid; // array of hexagons
let nbx, nby; // grid size (in elements, not pixels)
let orgx, orgy;
let perx, pery, pergrid;
let colorMode = 0;
let globalHue;

// for animation
let messages;

// shortcuts for Math.
const mrandom = Math.random;
const mfloor = Math.floor;
const mround = Math.round;
const mceil = Math.ceil;
const mabs = Math.abs;
const mmin = Math.min;
const mmax = Math.max;

const mPI = Math.PI;
const mPIS2 = Math.PI / 2;
const mPIS3 = Math.PI / 3;
const m2PI = Math.PI * 2;
const m2PIS3 = Math.PI * 2 / 3;
const msin = Math.sin;
const mcos = Math.cos;
const matan2 = Math.atan2;

const mhypot = Math.hypot;
const msqrt = Math.sqrt;

const rac3 = msqrt(3);
const rac3s2 = rac3 / 2;

//------------------------------------------------------------------------

function alea(mini, maxi) {
  // random number in given range

  if (typeof maxi == "undefined") return mini * mrandom(); // range 0..mini

  return mini + mrandom() * (maxi - mini); // range mini..maxi
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function intAlea(mini, maxi) {
  // random integer in given range (mini..maxi - 1 or 0..mini - 1)
  //
  if (typeof maxi == "undefined") return mfloor(mini * mrandom()); // range 0..mini - 1
  return mini + mfloor(mrandom() * (maxi - mini)); // range mini .. maxi - 1
}

function lerp(p0, p1, alpha) {
  return {
    x: p0.x * (1 - alpha) + p1.x * alpha,
    y: p0.y * (1 - alpha) + p1.y * alpha };

}
//------------------------------------------------------------------------

class ExtremeFilter {
  /* tracks extreme points to build a linear gradient in direction given by constructor
      let D the oriented straight line passing by (0,0) in direction D
      makes projection of filtered points on D
      keeps track of points whose projection has min and max abscissa on D
      */

  constructor(angle = 0) {
    this.min = Infinity;
    this.max = -Infinity;
    this.c = Math.cos(angle);
    this.s = Math.sin(angle);
  }

  filter(p) {
    let absc = p.x * this.c + p.y * this.s;
    if (absc < this.min) {
      this.min = absc;
      this.pmin = p;
    }
    if (absc > this.max) {
      this.max = absc;
      this.pmax = p;
    }
  } // filter

  filterArc(xc, yc, radius, starta, enda, ccw) {
    /* uses same signature as CanvasRenderingContext2D.arc
        does not accurately find extreme values, but filters a few points along the arc.
        Inaccuracy does not matter that much for a gradient
        */
    let x, y, a;
    // make angles increasing along arc
    if (ccw) [starta, enda] = [enda, starta];
    while (enda < starta) enda += m2PI;
    while (enda > starta + m2PI) enda -= m2PI;
    const ndiv = mceil((enda - starta) / 0.4); // vill divide arc in angles < 0.4 rad (0.4 : arbitrary value)
    if (ndiv == 0) ndiv = 1; // will do some extra work, but who cares ?
    for (let k = 0; k <= ndiv; ++k) {
      a = starta + k * (enda - starta) / ndiv;
      this.filter({ x: xc + radius * mcos(a), y: yc + radius * msin(a) });
    }
  } // filterArc

  getLinearGradient() {
    /* creates a gradient without filling the stop points */
    let delta = this.max - this.min;
    return ctx.createLinearGradient(
    this.pmin.x,
    this.pmin.y,
    this.pmin.x + delta * this.c,
    this.pmin.y + delta * this.s);

  }}
// ExtremeFilter

//------------------------------------------------------------------------
/* angles useful for the arcs */
const deltaAng0 = Math.acos(msqrt(2 / 3));
//    const deltaAng1 = mPIS3 - deltaAng0;

class Hexagon {
  constructor(kx, ky) {
    this.kx = kx;
    this.ky = ky;
    //        this.rot = intAlea(6); // random orientation
    this.rot = pergrid[ky % pery][kx % perx].rot;
    this.arcTypes = [];
    this.exits = [];
    this.turn = [];
    for (let k = 0; k < 6; ++k) {
      this.exits[(k + this.rot) % 6] = ([5, 4, 1, 2, 3, 0][k] + this.rot) % 6;
      this.turn[(k + this.rot) % 6] = [2, 0, 2, 2, 2, -2][k]; // in 1/6th of turn
      this.arcTypes[(k + this.rot) % 6] = ["l", "b", "b", "b", "b", "l"][k];
      /* encoding for arcTypes l/b = little/big */
    }

    this.size();
    this.lines = [];
  } // Hexagon.constructor

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  size() {
    // coordinates of centre
    this.xc = orgx + this.kx * 1.5 * radius;
    this.yc = orgy + this.ky * radius * rac3;
    if (this.kx & 1) this.yc -= radius * rac3s2; // odd columns, centre is a bit higher

    this.vertices = new Array(6).fill(0).map((v, k) => ({
      x: this.xc + radius * mcos((k - 2) * mPI / 3),
      y: this.yc + radius * msin((k - 2) * mPI / 3) }));

    this.vertices[6] = this.vertices[0]; // makes things easier by avoiding many "% 6" in calculating other calculations

    this.middle = new Array(6).
    fill(0).
    map((p, k) => lerp(this.vertices[k], this.vertices[k + 1], 0.5));

    this.extCenters = new Array(6).fill(0).map((v, k) => ({
      x: this.xc + rac3 * radius * mcos(k * mPI / 3 - mPIS2),
      y: this.yc + rac3 * radius * msin(k * mPI / 3 - mPIS2) }));

  } // Hexagon.prototype.size

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  drawLittleArc(kCenter) {
    ctx.beginPath();
    ctx.arc(
    this.vertices[kCenter].x,
    this.vertices[kCenter].y,
    radius / 2,
    kCenter * mPI / 3,
    (kCenter + 2) * mPIS3);

    ctx.stroke();
  }
  drawBigArc(kCenter) {
    ctx.beginPath();
    ctx.arc(
    this.extCenters[kCenter].x,
    this.extCenters[kCenter].y,
    1.5 * radius,
    (kCenter + 1) * mPI / 3,
    (kCenter + 2) * mPIS3);

    ctx.stroke();
  }
  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  drawArcs() {
    let c, radius, a0, a1, ccw;
    ctx.lineWidth = 2;
    ctx.strokeStyle = "#fff";

    for (let k = 0; k < 6; ++k) {
      if ((k - this.rot + 6) % 6 == 5) continue;
      ({ c, radius, a0, a1, ccw } = this.getArcElements(k));
      ctx.beginPath();
      ctx.arc(c.x, c.y, radius, a0, a1, ccw);
      ctx.stroke();
    }
  } //Hexagon.prototype.drawArcs

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  getArcElements(kEntry) {
    // arcs are defined starting from kEntry

    // returns (center, radius, a0,a1, ccw)
    switch ((kEntry + 6 - this.rot) % 6) {
      case 0:
        return {
          c: this.vertices[this.rot],
          radius: 0.5 * radius,
          a0: this.rot * mPIS3,
          a1: (this.rot + 2) * mPIS3,
          ccw: false };


      case 1:
        return {
          c: this.extCenters[(this.rot + 2) % 6],
          radius: 1.5 * radius,
          a0: (this.rot + 4) % 6 * mPIS3,
          a1: (this.rot + 4) % 6 * mPIS3 - deltaAng0,
          ccw: true };


      case 2:
        return {
          c: this.extCenters[(this.rot + 3) % 6],
          radius: 1.5 * radius,
          a0: (this.rot + 5) % 6 * mPIS3,
          a1: (this.rot + 4) % 6 * mPIS3 + deltaAng0,
          ccw: true };


      case 3:
        return {
          c: this.extCenters[(this.rot + 2) % 6],
          radius: 1.5 * radius,
          a0: (this.rot + 3) % 6 * mPIS3,
          a1: (this.rot + 4) % 6 * mPIS3 - deltaAng0,
          ccw: false };


      case 4:
        return {
          c: this.extCenters[(this.rot + 3) % 6],
          radius: 1.5 * radius,
          a0: (this.rot + 4) % 6 * mPIS3,
          a1: (this.rot + 4) % 6 * mPIS3 + deltaAng0,
          ccw: false };


      case 5:
        return {
          c: this.vertices[this.rot],
          radius: 0.5 * radius,
          a0: (this.rot + 2) * mPIS3,
          a1: this.rot * mPIS3,
          ccw: true };}


  }

  getReverseArcElements(kExit) {
    const el = this.getArcElements(kExit);
    return { c: el.c, radius: el.radius, a0: el.a1, a1: el.a0, ccw: !el.ccw };
  } // getReverseArcElements

  getCrossingElements(kEntry, kExit) {
    /* returns array of 1 or 2 arcElements, suitably oriented */
    if (this.arcTypes[kEntry] == "l")
      // little arc: only one
      return [this.getArcElements(kEntry)];
    return [this.getArcElements(kEntry), this.getReverseArcElements(kExit)];
  } // getCrossingElements

  drawHexagon() {
    ctx.beginPath();
    this.vertices.forEach((p, k) => {
      if (k == 0) ctx.moveTo(p.x, p.y);else
      ctx.lineTo(p.x, p.y);
    });
    ctx.lineWidth = 0.25;
    ctx.strokeStyle = "#fff";
    ctx.stroke();
  } // Hexagon.prototype.drawHexagon

  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  getNeighbor(edge) {
    const kx = this.kx + [0, 1, 1, 0, -1, -1][edge];
    const ky =
    this.ky +
    [
    [-1, 0, 1, 1, 1, 0],
    [-1, -1, 0, 1, 0, -1]][
    this.kx & 1][edge];
    if (kx < 0 || kx >= nbx || ky < 0 || ky >= nby) return false;
    return grid[ky][kx];
  }}
//class Hexagon
//-----------------------------------------------------------------------------
class Hierarchy {
  constructor(item) {
    this.item = item;
    this.children = [];
  }
  isDeeper(other) {
    // "other" is deeper than "this" ?
    /* "deeper" means "inside" in the context of nesting loops */
    /* to build hierarchy : returns true if other must be in this's chidren (or grandchildren)
         returning false DOES NOT imply that other.isDeeper(this) returns true : they may be siblings or not directly related
        */
    if (!this.item) return true; // "this" is top of hierarchy, all others are lower
    return ctx.isPointInPath(
    this.item.path,
    other.item.refP.x,
    other.item.refP.y);

  }

  insert(other) {
    /* must be called only if isDeeper(other) returs true (actually checked, or this is top) */
    for (let k = 0; k < this.children.length; ++k) {
      if (this.children[k].isDeeper(other)) {
        // belongs to a child
        this.children[k].insert(other);
        return;
      }
    }
    // see if other is any of my children's ancestor
    for (let k = this.children.length - 1.........完整代码请登录后点击上方下载按钮下载查看

网友评论0