291 Codepen

Генератор спиралей

Генератор анимированных разноцветных спиралей. 


HTML

<canvas id="canvas"></canvas>

SCSS

body {
  margin: 0;
  height: 100vh;
  overflow: hidden;
  background: url(https://raw.githubusercontent.com/supahfunk/supah-codepen/master/spiral.jpg);
  background-size: cover;
}

.dg.main .close-button,
.dg li.title {
  background: #111!important;
}

img {
  position: a
}

JS

https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.6/dat.gui.min.js
скрипт:
/*--------------------
Utils
--------------------*/
const scale = (v, x1, y1, x2, y2) => (v - x1) * (y2 - x2) / (y1 - x1) + x2;
const deg = (a) => a * Math.PI / 180 
const turnAround = (t) => t * deg(360)


/*--------------------
Settings
--------------------*/
const settings = {
  times: 10,
  startRadius: 0,
  endRadius: 300,
  startStroke: 15,
  endStroke: 50,
  offsetX: deg(-.5),
  offsetY: 0,
  startColor: 'rgb(123,0,7)',
  endColor: 'rgb(255,185,18)',
  backgroundColor: 'rgb(0, 0, 0)',
  speed: 1,
}


/*--------------------
Setup
--------------------*/
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
const win = {
  w: window.innerWidth,
  h: window.innerHeight
}
const mouse = {
  x: win.w / 2,
  y: win.h / 2,
}
let loop = 0
let animation = 0


/*--------------------
Listeners
--------------------*/
window.addEventListener('resize', () => {
  win.w = window.innerWidth
  win.h = window.innerHeight
})

window.addEventListener('mousemove', (e) => {
  mouse.x = e.clientX
  mouse.y = e.clientY
})


/*--------------------
Reset
--------------------*/
const reset = () => {
  canvas.width = win.w * 2
  canvas.height = win.h * 2
  canvas.style.width = `${win.w}px`
  canvas.style.height = `${win.h}px`
  ctx.fillStyle = settings.backgroundColor
  ctx.fillRect(0, 0, win.w * 2, win.h * 2)
  ctx.closePath()
  ctx.scale(2, 2)
  ctx.translate(win.w / 2, win.h / 2)
}


/*--------------------
Generate Vortex
--------------------*/
const vortex = () => {
  const times = turnAround(settings.times)
  for (let i = 0; i < times; i += deg(1)) {
    
    const c1 = settings.startColor.match(/\d+/g).map(Number)
    const c2 = settings.endColor.match(/\d+/g).map(Number)
    const r = scale(i, 0, times, c1[0], c2[0])
    const g = scale(i, 0, times, c1[1], c2[1])
    const b = scale(i, 0, times, c1[2], c2[2])
    const color = `rgba(${r}, ${g}, ${b})`
    ctx.fillStyle = color
    
    const width = scale(i, 0, times, settings.startStroke, settings.endStroke)
    ctx.lineWidth = width
    
    const radius = scale(i, 0, turnAround(settings.times), settings.startRadius, settings.endRadius)
    const x = (Math.sin(i + animation) + (settings.offsetX * i)) * radius
    const y = (Math.cos(i + animation) + (settings.offsetY * i)) * radius 
    
    ctx.beginPath()
    ctx.arc(x, y, width, 0, deg(360))
    ctx.fill()
    ctx.closePath()
  }
}


/*--------------------
Dat Gui
--------------------*/
const randomize = () => {
  settings.times = Math.random() * 20
  settings.startRadius = Math.random() * win.w / 4
  settings.endRadius = Math.random() * win.w / 4
  settings.startStroke = Math.random() * 130
  settings.endStroke = Math.random() * 130
  settings.offsetX = deg(-1 + Math.random() * 2)
  settings.offsetY = deg(-1 + Math.random() * 2)
  const c1 = [
    Math.floor(Math.random() * 200),
    Math.floor(Math.random() * 200),
    Math.floor(Math.random() * 200),
  ]
  const c2 = [
    Math.floor(Math.random() * 200),
    Math.floor(Math.random() * 200),
    Math.floor(Math.random() * 200),
  ]
  settings.startColor = `rgba(${c1[0]}, ${c1[1]}, ${c1[2]})`
  settings.endColor = `rgba(${c2[0]}, ${c2[1]}, ${c2[2]})`
  gui.destroy()
  datgui()
}


/*--------------------
Dat Gui
--------------------*/
const saveImage = () => {
  const image = canvas.toDataURL("image/png")
  const a = document.createElement('a')
  a.href = image
  a.setAttribute('download', '')
  console.log(a)
  document.body.appendChild(a)
  a.click()
}


/*--------------------
Dat Gui
--------------------*/
let gui
const datgui = () => {
  gui = new dat.GUI()
  let f1 = gui.addFolder('Loops');
  f1.add(settings, "times", 1, 20).step(deg(1))
  f1.add(settings, "speed", 0, 10).step(1)
  f1.open()
  
  let f2 = gui.addFolder('Radius');
  f2.add(settings, "startRadius", 0, win.w * 0.7).step(1)
  f2.add(settings, "endRadius", 0, win.w * 0.7).step(1)
 
  let f3 = gui.addFolder('Stroke');
  f3.add(settings, "startStroke", 1, 200).step(1)
  f3.add(settings, "endStroke", 1, 200).step(1)
  
  let f4 = gui.addFolder('Offset');
  f4.add(settings, "offsetX", -deg(4), deg(4)).step(deg(.1))
  f4.add(settings, "offsetY", -deg(4), deg(4)).step(deg(.1))
  
  let f5 = gui.addFolder('Colors');
  f5.addColor(settings, "startColor")
  f5.addColor(settings, "endColor")
  f5.addColor(settings, "backgroundColor")
  
  const save = { Download: () => saveImage() }
  gui.add(save, 'Download');
  
  console.log(settings)
  if (win.w < 500) {
    gui.close()
  }  
}
datgui()
vortex()

/*--------------------
Animate
--------------------*/
const animate = () => {
  animation = settings.speed * loop
  reset()
  vortex()
  loop += 0.01
  requestAnimationFrame(animate)
}
animate()
Демо

Комментарии

  • Facebook
  • Вконтакте

Похожие статьи