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;
  cursor: pointer;
  overflow: hidden;
}

input {
  caret-color: auto;
}

#menu {
  font-size: 80%;
  margin: 0;
  padding: 5px;
  position: absolute;
  left: 5px;
  top: 5px;
  border-radius: 10px;
  background-color: rgba(255, 255, 128, 0.9);
  color: black;
  z-index: 10;
}

#menu.hidden #showhide {
  display: none;
}

#controls {
  margin-top: 0px;
  margin-bottom: 0px;
  text-align: right;
}

#controls:hover {
  background-color: rgba(255, 200, 128, 0.9);
}

#menu button {
  margin-right: 5px;
  margin-left: 5px;
  border-radius: 5px;
}

#menu .center {
  text-align: center;
}

#colorspan {
  margin: 0 5px;
  padding: 0 2em;
  border: 1px solid black;
}

canvas#displaycolor {
  width: 5em;
  height: 1.25em;
  border: 1px solid black;
}
</style>

  
  
  
</head>

<body translate="no">
  <div id="menu">
  <p id="controls">close controls</p>
  <div id="showhide">
    <hr>
    <p>field type: <select id="mode">
        <option value="0">parallel</option>
        <option value="1">mixed</option>
        <option value="2">perpendicular</option>
        <option value="3">noise</option>
        <option value="4" selected>eddies</option>
      </select></p>
    <hr>
    <p>paint mode: <select id="paintmode">
        <option value="0">automatic</option>
        <option value="1">manual</option>
      </select></p>
    <p>color choice mode: <select id="colorchoicemode">
        <option value="0">automatic</option>
        <option value="1">manual</option>
      </select></p>
    <p>color: <input type="color" id="color" value="#ffa000"></p>
    <p>sat/lum randomness: </p>
    <p><input type="range" min=0 max=1 step="any" value=0.5 id="fibrosity"> <canvas id="displaycolor"></canvas></p>
    <p>line width: <input type="range" min=0.1 max=4 step="any" value=3 id="lwidth"></p>
    <hr>
    <p class="center"><button type="button" id="clear">new</button> <button type="button" id="clearsamefield">new -
        same field</button></p>
  </div> <!-- showhide -->
</div> <!-- menu -->
  
      <script >
"use strict";

const NB_BARS = 10;
const NB_EDDIES = 7;
const BASE_SPEED = 2; // for bars only

const MAX_LIFETIME = 5000;

let canv, ctx; // canvas and context
let maxx, maxy; // canvas dimensions
let lRef;
let perpMode;
let mouse = {};

let fx, speed, perNoise; // for noise field
let bars, eddies;
let fieldFunction;
let colorizer, filler;

// for animation
let messages;
// user interface
let ui, uiv;

// 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 mexp = Math.exp;

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 distance(pa, pb) {
  return mhypot(pa.x - pb.x, pa.y - pb.y);
} // distance
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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 arrayShuffle(array) {
  /* randomly changes the order of items in an array
               only the order is modified, not the elements
            */
  let k1, temp;
  for (let k = array.length - 1; k >= 1; --k) {
    k1 = intAlea(0, k + 1);
    temp = array[k];
    array[k] = array[k1];
    array[k1] = temp;
  } // for k
  return array;
} // arrayShuffle
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/**
 * Converts an RGB color value to HSL. Conversion formula
 * adapted from http://en.wikipedia.org/wiki/HSL_color_space.
 * Assumes r, g, and b are contained in the set [0, 255] and
 * returns h, s, and l in the set [0, 1].
 */
function rgbToHsl(r, g, b) {
  r /= 255, g /= 255, b /= 255;
  var max = Math.max(r, g, b),
  min = Math.min(r, g, b);
  var h,
  s,
  l = (max + min) / 2;

  if (max == min) {
    h = s = 0; // achromatic
  } else {
    var d = max - min;
    s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
    switch (max) {
      case r:
        h = (g - b) / d + (g < b ? 6 : 0);
        break;
      case g:
        h = (b - r) / d + 2;
        break;
      case b:
        h = (r - g) / d + 4;
        break;}

    h /= 6;
  }

  return [h, s, l];
} // function rgbToHsl
//------------------------------------------------------------------------
// User Interface (controls)
//------------------------------------------------------------------------
function toggleMenu() {
  if (menu.classList.contains("hidden")) {
    menu.classList.remove("hidden");
    this.innerHTML = "close controls";
  } else {
    menu.classList.add("hidden");
    this.innerHTML = "controls";
  }
} // toggleMenu

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

function getCoerce(name, min, max, isInt) {
  let parse = isInt ? parseInt : parseFloat;
  let ctrl = ui[name];
  let x = parse(ctrl.value, 10);
  if (isNaN(x)) {
    x = uiv[name];
  }
  x = mmax(x, min);
  x = mmin(x, max);
  ctrl.value = uiv[name] = x;
}

//------------------------------------------------------------------------
function prepareUI() {
  // toggle menu handler

  document.querySelector("#controls").addEventListener("click", toggleMenu);

  ui = {}; // User Interface HTML elements
  uiv = {}; // User Interface values of controls

  [
  "paintmode",
  "colorchoicemode",
  "color",
  "displaycolor",
  "mode",
  "clear",
  "lwidth",
  "clearsamefield",
  "fibrosity"].
  forEach(ctrlName => ui[ctrlName] = document.getElementById(ctrlName));
  const rect = ui.displaycolor.getBoundingClientRect();
  ui.displaycolor.width = rect.width - 2; // -2 for border - not that important
  ui.displaycolor.height = rect.height - 2;
  registerControl("paintmode", readUIInt, "input");
  registerControl("colorchoicemode", readColorChoiceMode, "input");
  registerControl("color", readColor, "input");
  registerControl("mode", readUIInt, "input");
  registerControl("lwidth", readUIFloat, "input");
  registerControl("fibrosity", readCoerced, "input", displayColor);
  ui.clear.addEventListener("click", () => messages.push({ message: "reset" }));
  ui.clearsamefield.addEventListener("click", clearSameField);
  readUI();
} // prepareUI

//------------------------------------------------------------------------
function readUI() {
  if (ui.registered) {
    for (const ctrl in ui.registered) ui.registered[ctrl].readF();
  }
  displayColor();
  readColorChoiceMode.call(ui.colorchoicemode);
} // readUI

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function registerControl(
controlName,
readFunction,
changeEvent,
changedFunction)
{
  /* provides simple way to associate controls with their read / update / changeEvent / changed functions
            since many (but not all) controls work almost the same way */
  /* changeEvent and changedFunction are optional */

  const ctrl = ui[controlName];
  ui.registered = ui.registered || [];
  ui.registered.push(ctrl); // NEVER register a control twice !!!
  ctrl.readF = readFunction;
  if (changeEvent) {
    ctrl.addEventListener(changeEvent, event => {
      readFunction.call(ctrl);
      if (changedFunction) changedFunction.call(ctrl, event);
    });
  }
} // registerControl
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function readUIFloat() {
  uiv[this.id] = parseFloat(this.value);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function readUIInt() {
  uiv[this.id] = parseInt(this.value);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function readUICheck() {
  uiv[this.id] = this.checked;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function readColor() {
  const raw = this.value;
  const color = { raw };
  color.r = parseInt(raw.substring(1, 3), 16);
  color.g = parseInt(raw.substring(3, 5), 16);
  color.b = parseInt(raw.substring(5, 7), 16);
  const hsl = rgbToHsl(color.r, color.g, color.b);
  color.h = 360 * hsl[0];
  color.s = 100 * hsl[1];
  color.l = 100 * hsl[2];
  uiv[this.id] = color;
  displayColor();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function readColorChoiceMode() {
  readUIInt.call(this);
  if (uiv.colorchoicemode) {
    ui.color.removeAttribute("disabled"); // manual;
  } else {
    ui.color.setAttribute("disabled", ""); // automatic
  }
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function readCoerced() {
  /* the element will be read with getCoerce with values given by its min, max and step attributes
              (integer value if step == 1)
            */
  let min = this.getAttribute("min");
  let max = this.getAttribute("max");
  let step = this.getAttribute("step");
  getCoerce(this.id, min, max, step == 1);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
function displayColor() {
  let ctx = ui.displaycolor.getContext("2d");

  ctx.lineWidth = 1;
  for (let ky = 0; ky < ui.displaycolor.height; ++ky) {
    ctx.beginPath();
    ctx.moveTo(0, ky);
    ctx.lineTo(ui.displaycolor.width, ky);
    ctx.strokeStyle = lineColor();
    ctx.stroke();
  }
}

//------------------------------------------------------------------------
/*
 * A fast javascript implementation of simplex noise by Jonas Wagner
 *
 * Based on a speed-improved simplex noise algorithm for 2D, 3D and 4D in Java.
 * Which is based on example code by Stefan Gustavson (stegu@itn.liu.se).
 * With Optimisations by Peter Eastman (peastman@drizzle.stanford.edu).
 * Better rank ordering method by Stefan Gustavson in 2012.
 *
 *
 * Copyright (C) 2012 Jonas Wagner
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the S.........完整代码请登录后点击上方下载按钮下载查看

网友评论0