JSFiddle - React, Tailwind, and code Playground

by knrm720

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/bacon.js/0.7.53/Bacon.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stats.js/r11/Stats.js"></script>
<script src="https://cdn.jsdelivr.net/kefir/3.1.0/kefir.js"></script>
<p>
  In this demo each branch of the tree represented by two streams
  (Top and Angle) and has a parent branch. The Angle stream depends on
  parent's Angle and on additional Oscillation stream.
  A Top stream depends on parent's Top and self Angle streams.
  Having parent's Top and child's Top we can draw a line,
  all these lines form the tree, that you can see right now.
</p>

<label>
  Library:
  <select id="lib">
    <option value="Kefir">Kefir</option>
    <option value="Bacon">Bacon</option>
  </select>
</label>
<br>
<label>
  Depth:
  <select id="depth">
    <option value="1">1</option>
    <option value="2">2</option>
    <option value="3">3</option>
    <option value="4">4</option>
    <option value="5">5</option>
    <option value="6">6</option>
    <option value="7">7</option>
    <option value="8">8</option>
    <option value="9">9</option>
    <option value="10">10</option>
    <option value="11">11</option>
    <option value="12">12</option>
    <option value="13">13</option>
    <option value="14">14</option>
    <option value="15">15</option>
    <option value="16">16</option>
    <option value="17">17</option>
    <option value="18">18</option>
  </select>
</label>
<br>
<label>
  <input type="checkbox" id="partial-render"> Do not render all branches, just calculate
</label>

<br>
Total branches: <strong id="total"></strong>
<br>

<canvas id="canvas" width="500" height="300"></canvas>

CoffeeScript

# parse URL query

window.queryParams = do ->
  result = {}
  for param in location.search.slice(1).split('&')
    [key, value] = param.split('=')
    result[key] = value
  result

window.getParam = (name, notFound) ->
  if (name of queryParams)
    queryParams[name]
  else
    notFound

DEFAULT_DEPTH = 7
DEFAULT_LIB = 'Kefir'







# Setup selects

$('#lib').val(getParam('lib', DEFAULT_LIB)).change ->
  location.search = "?lib=#{ $(this).val() }&depth=#{ getParam('depth', DEFAULT_DEPTH) }&partial_render=#{ getParam('partial_render', 'no') }"
$('#depth').val(getParam('depth', DEFAULT_DEPTH)).change ->
  location.search = "?lib=#{ getParam('lib', DEFAULT_LIB) }&depth=#{ $(this).val() }&partial_render=#{ getParam('partial_render', 'no') }"
$('#partial-render').prop('checked', getParam('partial_render') == 'yes').change ->
  val = if $(this).prop('checked') then 'yes' else 'no'
  location.search = "?lib=#{ getParam('lib', DEFAULT_LIB) }&depth=#{ getParam('depth', DEFAULT_DEPTH) }&partial_render=#{ val }"

PARTIAL_RENDER = (getParam('partial_render') == 'yes')






# Setup canvas

lines = []

canvasEl = document.getElementById('canvas')
ctx = canvasEl.getContext('2d')
ctx.strokeStyle = "green"


stats = new Stats()
document.body.appendChild( stats.domElement )

renderLoop = ->
  stats.begin()
  stats.end()
  ctx.clearRect(0, 0, 500, 300)
  for line in lines
    if !PARTIAL_RENDER || line.width >= 1
      ctx.beginPath()
      ctx.moveTo(line.x1, line.y1)
      ctx.lineTo(line.x2, line.y2)
      ctx.lineWidth = line.width;
      ctx.stroke()
  requestAnimationFrame(renderLoop)
renderLoop()




# Utils

randomize = (x, a = .1) ->
  x * (Math.random() * a * 2 + 1 - a)

oscillationGenerator = (ticks) ->
  (frequency) ->
    min = 0
    max = Math.PI * 2
    cur = 0
    add = Math.PI / 25 * frequency
    ticks.map ->
      cur += add
      Math.sin(cur)








# Branch represents tree branch

class BranchKefir

  oscillation: oscillationGenerator(Kefir.interval(1000 /...