外文翻译 | 你以为你会用Math.random() ? 不,你不会……

文章目录

    • 制造动画效果
      • HTML
      • CSS
      • JavaScript
    • 电子音乐
      • HTML
      • SCSS
      • CoffeeScript
    • 随机显示图片
      • HTML
      • CSS
      • JavaScript
    • 随机背景颜色
      • Pug
      • SCSS
      • Babel
    • 艺术效果
      • HTML
      • CSS
      • JavaScript
    • 文字效果
      • Slim
      • Sass
      • JavaScript
    • API密钥生成器
      • HTML
      • CSS
      • JavaScript
    • 打乱文本
      • HTML
      • Stylus
      • Babel
    • 石头剪刀布
      • HTML
      • SCSS
      • JavaScript
    • 密码生成器
      • HTML
      • SCSS
      • JavaScript
  • 值得关注的事情
    • Math.random()真的是随机的吗?
    • 如何处理重复值?
    • Math.random()与WebCrypto相同吗?

原文来源:https://css-tricks.com/lots-of-ways-to-use-math-random-in-javascript/

Math.random()是JavaScript中的一个API。能够为您提供一个随机数的功能。 返回的数字将介于0(包括0)和1(不包括1)之间。

Math.random()//返回一个小于1的随机数(不包含1)

Math.random()函数对于游戏,动画,随机数据,艺术效果,随机文本生成等许多方面非常有用! 它可以用于Web开发,移动应用程序,计算机程序和视频游戏。

每当我们在工作中需要使用随机数据时,就可以使用此功能! 让我们看一下我们使用它的八种不同方式。 这些示例均来自不同的作者,利用这一API进行了一些有趣的创作。

制造动画效果

HTML

<canvas id=c>canvas>

CSS

canvas {  
  position: absolute;
  top: 0;
  left: 0;
}

JavaScript

var w = c.width = window.innerWidth,
    h = c.height = window.innerHeight,
    ctx = c.getContext( '2d' ),    
    opts = {      
      len: 20,
      count: 50,
      baseTime: 10,
      addedTime: 10,
      dieChance: .05,
      spawnChance: 1,
      sparkChance: .1,
      sparkDist: 10,
      sparkSize: 2,      
      color: 'hsl(hue,100%,light%)',
      baseLight: 50,
      addedLight: 10, // [50-10,50+10]
      shadowToTimePropMult: 6,
      baseLightInputMultiplier: .01,
      addedLightInputMultiplier: .02,      
      cx: w / 2,
      cy: h / 2,
      repaintAlpha: .04,
      hueChange: .1
    },
    tick = 0,
    lines = [],
    dieX = w / 2 / opts.len,
    dieY = h / 2 / opts.len,    
    baseRad = Math.PI * 2 / 6;
    
ctx.fillStyle = 'black';
ctx.fillRect( 0, 0, w, h );

function loop() {
  
  window.requestAnimationFrame( loop );
  
  ++tick;
  
  ctx.globalCompositeOperation = 'source-over';
  ctx.shadowBlur = 0;
  ctx.fillStyle = 'rgba(0,0,0,alp)'.replace( 'alp', opts.repaintAlpha );
  ctx.fillRect( 0, 0, w, h );
  ctx.globalCompositeOperation = 'lighter';
  
  if( lines.length < opts.count && Math.random() < opts.spawnChance )
    lines.push( new Line );
  
  lines.map( function( line ){ line.step(); } );
}
function Line(){
  
  this.reset();
}
Line.prototype.reset = function(){
  
  this.x = 0;
  this.y = 0;
  this.addedX = 0;
  this.addedY = 0;
  
  this.rad = 0;
  
  this.lightInputMultiplier = opts.baseLightInputMultiplier + opts.addedLightInputMultiplier * Math.random();
  
  this.color = opts.color.replace( 'hue', tick * opts.hueChange );
  this.cumulativeTime = 0;
  
  this.beginPhase();
}
Line.prototype.beginPhase = function(){
  
  this.x += this.addedX;
  this.y += this.addedY;
  
  this.time = 0;
  this.targetTime = ( opts.baseTime + opts.addedTime * Math.random() ) |0;
  
  this.rad += baseRad * ( Math.random() < .5 ? 1 : -1 );
  this.addedX = Math.cos( this.rad );
  this.addedY = Math.sin( this.rad );
  
  if( Math.random() < opts.dieChance || this.x > dieX || this.x < -dieX || this.y > dieY || this.y < -dieY )
    this.reset();
}
Line.prototype.step = function(){
  
  ++this.time;
  ++this.cumulativeTime;
  
  if( this.time >= this.targetTime )
    this.beginPhase();
  
  var prop = this.time / this.targetTime,
      wave = Math.sin( prop * Math.PI / 2  ),
      x = this.addedX * wave,
      y = this.addedY * wave;
  
  ctx.shadowBlur = prop * opts.shadowToTimePropMult;
  ctx.fillStyle = ctx.shadowColor = this.color.replace( 'light', opts.baseLight + opts.addedLight * Math.sin( this.cumulativeTime * this.lightInputMultiplier ) );
  ctx.fillRect( opts.cx + ( this.x + x ) * opts.len, opts.cy + ( this.y + y ) * opts.len, 2, 2 );
  
  if( Math.random() < opts.sparkChance )
    ctx.fillRect( opts.cx + ( this.x + x ) * opts.len + Math.random() * opts.sparkDist * ( Math.random() < .5 ? 1 : -1 ) - opts.sparkSize / 2, opts.cy + ( this.y + y ) * opts.len + Math.random() * opts.sparkDist * ( Math.random() < .5 ? 1 : -1 ) - opts.sparkSize / 2, opts.sparkSize, opts.sparkSize )
}
loop();

window.addEventListener( 'resize', function(){  
  w = c.width = window.innerWidth;
  h = c.height = window.innerHeight;
  ctx.fillStyle = 'black';
  ctx.fillRect( 0, 0, w, h );
  
  opts.cx = w / 2;
  opts.cy = h / 2;
  
  dieX = w / 2 / opts.len;
  dieY = h / 2 / opts.len;
});

生成一个对象并使其动画化,我们使用Math.random。霓虹灯线形成自发的六边形,同时利用随机化产生火花效果。

电子音乐

HTML

<header>
  <h1>Random Musich1>
  <p>Using the characteristics of <em>Auld Lang Syneem>p>
header>
<section id="staff">
section>
<div class="triggers">
  <a id="play">
    <span class="play">span>
    <span class="stop">span>
  a>
  <a id="new">New Songa>
div>

SCSS

import url(https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,300italic|Inconsolata);
$c-primary: #545454;
$c-dark: darken($c-primary,10%);
$c-black: darken($c-dark,20%);
$c-med: lighten($c-primary,10%);
$c-gray: #c0c0c0;
$c-light: #f0f0f0;
$c-white: #ffffff;
$c-off-white: transparentize($c-white, 0.8);
$c-barely-white: transparentize($c-white, 0.9);

$clef_h: 100px;
#staff {
  height: $clef_h * 2;
  width: 95%;
  margin: 4em auto;
  position: relative;
  .clef {
    height: $clef_h;
    width: 100%;
    position: relative;
    margin-bottom: 24px;
    .beat {
      display: block;
      position: absolute;
      top: 0; bottom: 0; 
      transition: background 200ms;
      &.sus {
        z-index: 1;
      }
      &.chord {
        z-index: 2;
        font-size: 10px;
        $note-di: 4px;
        .note {
          transition: transform 500ms, background 100ms;
          position: absolute;
          left: 50%;
          transform: translate3d(-50%, -50%, 0) scale(1);
          background-color: $c-white;
          width: $note-di;
          height: $note-di;
          border-radius: 50%;
          @for $i from 0 through 36 {
            &.note-#{$i} {
              $ratio: $i / 36;
              top: $ratio * 100%;
              background-color: hsl($ratio * 360, 50%, 40%);  
            }
          }
        }
      }
      &.active {
        transition-duration: 50ms;
/*         background: $c-barely-white; */
        z-index: 9;
        .note {
          transform: translate3d(-50%, -50%, 0) scale(2);
          @for $i from 0 through 36 {
            &.note-#{$i} {
              $ratio: $i / 36;
              background-color: hsl($ratio * 360, 100%, 60%);  
            }
          }          
        }
      }
    }
  }
}

.triggers {
  width: 100%;
  text-align: center;
  $button-di: 40px;
  a {
    color: $c-white;
    font-weight: 100;
    cursor: pointer;
    display: block;
    margin: 0 auto;
    text-transform: uppercase;
    opacity: 0.8;
    width: 100px;
    transition: opacity 200ms;
    font-size: 2em;
    &.inactive {
      opacity: 0.3; 
      pointer-events: none;      
    }
    &:hover, &:active {
      opacity: 1;
    }
    &#play { 
      width: $button-di;
      height: $button-di;
      line-height: $button-di;
      border-radius: 50%;
      background-color: $c-off-white;
      margin-bottom: 12px;
      position: relative;
      .play, .stop {
        display: block;
        position: absolute;
        top: 50%;
        left: 50%;
      }
      .play {         
        border-left: 8px solid $c-white;
        border-top: 8px solid transparent;
        border-bottom: 8px solid transparent;
        transform: translate3d(-40%, -50%, 0);
      }      
      .stop {
        background-color: $c-white;
        height: 10px;
        width: 10px;
        transform: translate3d(-50%, -50%, 0);
        display: none;
      }      
      &.playing {
        .play { display: none;}      
        .stop { display: block;}
      }
    }
    &#new {
      font-size: 0.875em;
    }
  }
}


body {
  background-color: $c-black;
  font-family: 'Source Sans Pro';
  font-weight: 300;
  color: $c-white;
  header, article, #staff {
    transition: opacity 300ms;
  }
  #staff {
    opacity: 0.5;
  }
  &.playing {
    header, article {
      opacity: 0.4;
    }
    #staff {
      opacity: 1;
    }
  }
}
pre {
  font-family: 'Inconsolata';
  font-size: 0.9em;
  background-color: $c-barely-white;
  box-sizing: border-box;
  padding: 12px;
  em {
    font-style: normal;
    color: darken($c-white,70%);
  }
}
code {
  font-family: 'Inconsolata';
  font-size: 0.9em;
  padding: 6px;
  white-space: nowrap;
  background-color: $c-off-white;
}
h1, h2, h3 {
  font-weight: 300;
  text-transform: uppercase;
  letter-spacing: 0.125em;
}
h1 {
  margin-bottom: 0.25em;
}
h1 { font-size: 1.4em; }
h2 { font-size: 1.1em; }
h3 { font-size: 0.9em; }
h1, h2 {
  text-align: center;
}

header {
  text-align: center;    
  margin-top: 4em;
  h1, p {
    margin: 0;
  }
  p {
    margin-top: 0.5em;
    color: $c-light;
  }
}

article {
  width: 90%;
  max-width: 600px;
  margin: 8em auto;
  line-height: 1.8;
  text-align: justify;
  text-justify: inter-word;
  h1,h2 {
    margin-top: 1em;
  }
  h1, h2, h3 {
    margin-bottom: 0;
    & + p {
      margin-top: 0;
    }
  }
  a {
    color: $c-white;
  }
}

CoffeeScript

###
///
random music generator
jake albaugh
///
###
###
# globals
###
# generate a package of chances and values based on an object containing multiple possible zero values
ChancePkg = (vals) ->
  # generating vals and their chances of occuring
  new_vals = []
  # get total number of vals    
  vals_count = 0
  for value of vals
    if vals.hasOwnProperty(value) && vals[value] > 0
      vals_count += vals[value]
      new_vals.push [value, vals[value]]
  # go through new vals and generate chance for each value
  new_vals_chances = []  
  total = 0  
  for val, i in new_vals
    # relative amount for random selection    
    amount = total + ( (val[1] / vals_count ) * 100000)
    # push amount into chances array    
    new_vals_chances.push amount    
    # set value to be the value, no longer an array of data    
    new_vals[i] = parseInt(val[0])
    # increase base total    
    total = amount  
  # return package which has array for both non-zero vals and their corrosponding chance
  return {chances: new_vals_chances, vals: new_vals}



# get the sound to silence ratio at the smallest scale
getSoundRatio = (measures, beats, values) ->
  # generating vals and their chances of occuring
  new_values = []
  # get total number of vals    
  values_count = 0
  for value of values
    if values.hasOwnProperty(value) && values[value] > 0
      values_count += values[value]
      new_values.push [value, values[value]]  
  # resolution is the smallest sized note  
  resolution = (beats * (new_values[new_values.length - 1][1] / 4))
  # possible is how many resolution sized notes are in the piece  
  possible = measures * (beats * (resolution / 4))
  # usage to be used in the loop  
  usage = 0  
  for value in new_values
    # how many resolution values are in a single value? (ie. how many sixteenth notes are in a quarter note)    
    res_value = (1 / value[0]) * resolution
    # use resolution value * occurances    
    usage += res_value * value[1]    
  return usage / possible



# generate clef values based on data
Piece = (piece) ->
  {measures, beats, treble_clef, bass_clef, composition} = piece
  this.treble_clef = {
    # sound ratio is the presence of sound divided by the presenece of silence in the analyzed piece  
    sound_ratio: getSoundRatio(measures, beats, treble_clef.values)
    # value package has array for both non-zero values and their corrosponding chance
    values_pkg: new ChancePkg(treble_clef.values)
    # interval package has array for both non-zero intervals and their corrosponding chance
    intervals_pkg: new ChancePkg(treble_clef.intervals)
    # octaves package has array for both non-zero octaves and their corrosponding chance
    octaves_pkg: new ChancePkg(treble_clef.octaves)
    # chords package has array for both non-zero chords and their corrosponding chance
    chords_pkg: new ChancePkg(treble_clef.chords)
    # setting the base octave
    base_octave: 5
    # tone
    wave: 'sine'
    # gain
    gain: 0.3
  }
  this.bass_clef = {
    # sound ratio is the presence of sound divided by the presenece of silence in the analyzed piece  
    sound_ratio: getSoundRatio(measures, beats, bass_clef.values)
    # value package has array for both non-zero values and their corrosponding chance
    values_pkg: new ChancePkg(bass_clef.values)
    # interval package has array for both non-zero intervals and their corrosponding chance
    intervals_pkg: new ChancePkg(bass_clef.intervals)
    # octaves package has array for both non-zero octaves and their corrosponding chance
    octaves_pkg: new ChancePkg(bass_clef.octaves)
    # chords package has array for both non-zero chords and their corrosponding chance
    chords_pkg: new ChancePkg(bass_clef.chords)
    # setting the base octave
    base_octave: 3
    # tone
    wave: 'sine'
    # gain
    gain: 0.3
  }
  this.composition = composition
  return
  

  
# initiate audio context
audio_context = undefined
(init = (g) ->
  try
    # "crossbrowser" audio context.
    audio_context = new (g.AudioContext or g.webkitAudioContext)
  catch e
    console.log "No web audio oscillator support in this browser"
  return
) window



# oscillator prototype
Oscillator = (tone) ->
  max_gain = tone.gain
  this.tone = tone
  this.play = () ->
    # capturing current time for play start and stop
    current_time = audio_context.currentTime
    # create oscillator    
    o = audio_context.createOscillator()
    # create gain    
    gn = audio_context.createGain()    
    # set waveform    
    o.type = this.tone.wave
    # set frequency    
    if this.tone.frequency
      o.frequency.value = this.tone.frequency
    # connect oscillator to gain    
    o.connect gn
    # connect gain to output
    gn.connect audio_context.destination
    # set gain amount
    gn.gain.value = (max_gain / this.tone.vol) / 1
    # play it    
    o.start(current_time)
    # stop after sustain    
    o.stop(current_time + this.tone.sustain)
  return this



# note frequencies array of octave arrays that start on c (our root note)
freqs = [
  [16.351, 17.324, 18.354, 19.445, 20.601, 21.827, 23.124, 24.499, 25.956, 27.5, 29.135, 30.868]
  [32.703, 34.648, 36.708, 38.891, 41.203, 43.654, 46.249, 48.999, 51.913, 55, 58.27, 61.735]
  [65.406, 69.296, 73.416, 77.782, 82.407, 87.307, 92.499, 97.999, 103.826, 110, 116.541, 123.471]
  [130.813, 138.591, 146.832, 155.563, 164.814, 174.614, 184.997, 195.998, 207.652, 220, 233.082, 246.942]
  [261.626, 277.183, 293.665, 311.127, 329.628, 349.228, 369.994, 391.995, 415.305, 440, 466.164, 493.883]
  [523.251, 554.365, 587.33, 622.254, 659.255, 698.456, 739.989, 783.991, 830.609, 880, 932.328, 987.767]
  [1046.502, 1108.731, 1174.659, 1244.508, 1318.51, 1396.913, 1479.978, 1567.982, 1661.219, 1760, 1864.655, 1975.533]
  [2093.005, 2217.461, 2349.318, 2489.016, 2637.021, 2793.826, 2959.955, 3135.964, 3322.438, 3520, 3729.31, 3951.066]
  [4186.009, 4434.922, 4698.636, 4978.032, 5274.042, 5587.652, 5919.91, 6271.928, 6644.876, 7040, 7458.62, 7902.132]
  [8372.018, 8869.844, 9397.272, 9956.064, 10548.084, 11175.304, 11839.82, 12543.856, 13289.752, 14080, 14917.24, 15804.264]
]



# get random val from chance package
randomVal = (chance_pkg) ->
  random = Math.random() * 100000
  for chance, i in chance_pkg.chances
    return chance_pkg.vals[i] if random < chance
  return

# get sequence function
getSequence = (clef, composition) ->
  # get the duration in smallest resolution amount
  duration = composition.measures * (composition.beats * (composition.resolution / 4))  
  # note sequence
  sequence = []
  # while there is still duration
  while duration > 0
    # random hit
    random = Math.random()
    # if a hit    
    if random < clef.sound_ratio 
      # random chord note count
      chord = randomVal(clef.chords_pkg)
      # random length for the chord      
      value = randomVal(clef.values_pkg)
      # if there isnt enough space
      if ((1 / value) / (1 / composition.resolution)) >= duration
        # make it the length of remaining   
        value = ((1 / duration) / (1 / composition.resolution))
      # the new chord
      new_chord = {length: (1 / value), notes: []}
      # for each note in the chord      
      for note in [1..chord]
        # get a random interval
        interval = randomVal(clef.intervals_pkg)
        # get the random octave        
        octave = randomVal(clef.octaves_pkg)
        # make intervale relative to key
        interval += composition.root
        # if key pushes interval into new octave
        if interval > 12
          interval -= 12
        # make the octave relative to the clef's octave
        new_octave = clef.base_octave + ((2 - octave) * -1)
        # the frequency of the note
        note = freqs[new_octave - 1][interval]
        # if note doesnt already exist in chord
        if new_chord.notes.indexOf(note) == -1
          # push the frequency into the chord's notes        
          new_chord.notes.push {freq: note, int: interval, octave: octave}
        else
          # duplicate note in chord, ignoring it for now.
          console.log 'duplicate note in chord, ignoring it for now.'
      # push the chord into the sequence        
      sequence.push new_chord
      # get values resolution-relative value        
      res_value = Math.floor((1 / value) / (1 / composition.resolution))
      # if we need to add sustain notes                   
      if res_value > 1
        # add blank values      
        for blank in [1..res_value - 1]      
          sequence.push 'sus'
      # subtract from the duration      
      duration -= res_value
    else
      # it was a miss, add a zero to the sequence
      sequence.push 0
      # subtract tick from duration      
      duration--
  return sequence
Note = (tone) ->
  this.osc = () ->
    return new Oscillator(tone)
  returns
###
# data (to be derived from an analyzed piece of music)
###

piece = {
  # piece data (auld lang syne)
  measures: 16 # measures in analyzed piece
  beats:    4  # beats per measure in analyzed piece
  # all our analysis will be relative to each clef
  treble_clef: {  
    # note values are the duration of the note / chord. 
    # this is a map of how many times each value appears in the analyzed data
    values: {
      1:   0  # whole
      1.5: 4  # dotted half
      2:   5  # half
      3:   12 # dotted quarter
      4:   28 # quarter
      6:   0  # dotted eighth
      8:   12 # eighth
      12:  0  # dotted sixteenth
      16:  0  # sixteenth
      32:  0  # thirty-second
    }
    # relative to the key, the intervals are steps between notes and the root (no octaves)
    # this includes all single notes and instances of a note in a chord
    # this is a map of how many times each interval appears in the analyzed data
    intervals: {
      0:  32 # root / perfect unison (F)
      1:  0  # minor second (F#)
      2:  9  # major second (G)
      3:  0  # minor third (G#)
      4:  13 # major third (A)
      5:  0  # perfect fourth (A#)
      6:  6  # tritone (B)
      7:  13 # perfect fifth (C)
      8:  0  # minor sixth (C#)
      9:  15 # major sixth (D)
      10: 0  # minor seventh (D#)
      11: 12 # major seventh (E)
    }
    # octaves are how many times a note appears in each octave (relative to the key)
    octaves: {
      1: 37 # clef - 1
      2: 67 # clef
      3: 1  # clef + 1
    }
    # instead of using proper chords (dyad, triad, 7th, 9th, and 11th), we only analyze how many notes are in the chord
    # this is a map of how many times each chord size appears in the analyzed data
    chords: {
      1: 9  # 1 note
      2: 47 # 2 notes
      3: 0  # 3 notes
      4: 0  # 4 notes
      5: 0  # 5 notes
    }
  }
  bass_clef: {  
    # note values are the duration of the note / chord. 
    # this is a map of how many times each value appears in the analyzed data
    values: {
      1:   0  # whole
      1.5: 4  # dotted half
      2:   5  # half
      3:   12 # dotted quarter
      4:   28 # quarter
      6:   0  # dotted eighth
      8:   12 # eighth
      12:  0  # dotted sixteenth
      16:  0  # sixteenth
      32:  0  # thirty-second
    }
    # relative to the key, the intervals are steps between notes and the root (no octaves)
    # this includes all single notes and instances of a note in a chord
    # this is a map of how many times each interval appears in the analyzed data
    intervals: {
      0:  25 # root / perfect unison (F)
      1:  0  # minor second (F#)
      2:  1  # major second (G)
      3:  0  # minor third (G#)
      4:  17 # major third (A)
      5:  2  # perfect fourth (A#)
      6:  0  # tritone (B)
      7:  38 # perfect fifth (C)
      8:  1  # minor sixth (C#)
      9:  4  # major sixth (D)
      10: 0  # minor seventh (D#)
      11: 2  # major seventh (E)
    }
    # octaves are how many times a note appears in each octave (relative to the key)
    octaves: {
      1: 2  # clef - 1
      2: 53 # clef
      3: 50 # clef + 1
    }
    # instead of using proper chords (dyad, triad, 7th, 9th, and 11th), we only analyze how many notes are in the chord
    # this is a map of how many times each chord size appears in the analyzed data
    chords: {
      1: 9  # 1 note
      2: 46 # 2 notes
      3: 0  # 3 notes
      4: 0  # 4 notes
      5: 0  # 5 notes
    }

  }
  # defining the desired output composition data
  composition: {
    measures:   32  # bars to generate
    beats:      4   # beats per measure
    tempo:      120 # tempo
    resolution: 16  # resolution scale of piece  
    root:       5   # root of key (0-11), 0 is 'C'
  }
}


# lets analyze our piece data!
p = new Piece(piece)

# sequence stores
trebleSequence = undefined
bassSequence = undefined
# get sequences
getSequences = () ->
  # creating our treble clef
  trebleSequence = getSequence(p.treble_clef, p.composition)
  bassSequence = getSequence(p.bass_clef, p.composition)
  draw_sequences()

  
  
getSequenceHtml = (name, composition, sequence) ->
  $seq_html = $('
+ name + ' clef">
'
) beats = composition.measures * (composition.beats * (composition.resolution / 4)) width_increment = 1 / beats * 100 left = 0 for chord in sequence if typeof chord == "object" width = width_increment * (chord.length / (1 / composition.resolution)) width = width_increment classname = 'chord value-' + Math.round( (1 / chord.length) * 100) / 100 classname = classname.replace('.', '-') notes = '' for note in chord.notes out_of_36 = 36 - (note.int + ((note.octave - 1) * 12)) notes += '+ out_of_36 + '">' else if chord == 'sus' classname = 'sus' width = width_increment notes = '' else width = width_increment classname = 'blank' notes = '' $seq_html.append '+ classname + '" style="width: ' + width + '%; left: ' + left + '%">' + notes + '' left += width return $seq_html draw_sequences = () -> composition = p.composition $staffs = $('
'
) $staffs.append getSequenceHtml('treble', composition, trebleSequence) $staffs.append getSequenceHtml('bass', composition, bassSequence) $('#staff').html $staffs return performance_interval = undefined # play sequences playSequences = () -> composition = p.composition sequences = [trebleSequence, bassSequence] waves = [p.treble_clef.wave, p.bass_clef.wave] gains = [p.treble_clef.gain, p.bass_clef.gain] # total beat count beats = composition.measures * (composition.beats * (composition.resolution / 4)) # css width of beat beat_width = 100 / beats # relative index index = 0 # tempo to ms tempo_time = 60000 / composition.tempo # single beat instance next_beat = () -> for sequence, i in sequences chord = sequence[index] # if beat in any rhythm array has value if typeof chord == "object" # beats per second bps = composition.tempo / 60 # how much of a beat is the length beat_count = chord.length / 0.25 # sustain of the note in seconds chord_length_secs = beat_count * bps / 2 sustain = (chord_length_secs / bps) - 0.1 for note in chord.notes # new note n = new Note({frequency: note.freq, sustain: sustain, wave: waves[i], gain: gains[i], vol: chord.notes.length}) # new oscillator o = n.osc() # play oscillator o.play() if i == 0 then clef = 'treble' else clef = 'bass' if typeof chord == "object" $('.' + clef + ' .beat.active').removeClass 'active' $('.' + clef + ' .beat.go').removeClass clef + '-go' $('.' + clef + ' .beat:nth-child(' + (index + 1) + ')').addClass clef + '-go' else if chord != 'sus' $('.' + clef + ' .beat.active').removeClass 'active' $('.' + clef + ' .beat.go').removeClass clef + '-go' $('.beat:nth-child(' + (index + 1) + ')').addClass 'active' # update index index = (index + 1) % beats # first call of next beat next_beat() # ms to relative speed (based on resolution) time = tempo_time / (composition.resolution / 4) # set interval for next beat to occur at approriate time performance_interval = window.setInterval(next_beat, time) # stop button stopSequences = () -> window.clearInterval(performance_interval) # get sequences getSequences() playing = false play_handler = (p) -> if p == true playSequences() else stopSequences() playing = p $('#play').click () -> $(this).toggleClass 'playing' $('body').toggleClass 'playing' $('#new').toggleClass 'inactive' play_handler(!playing) $('#new').click () -> getSequences()

该程序采用传统的“ Auld Lang Syne”旋律,并在钢琴中弹奏随机音符。 根据计数数据创建一个更改包,并生成一个随机数来选择一个值。 八度音阶也是随机选择的。

随机显示图片

HTML

<html>
  <head>
    <title>Random Picture Generatortitle>
    <link rel="stylesheet" href="assets/stylesheets/app.css">
  head>
  <body>
    <header class="flex">
      <h1>Random Picture Generatorh1>
      <button>Generate Random Picturebutton>
    header>
    <section class="flex">
      <img src="">
    section>
    <script src="assets/scripts/app.js">script>
  body>
html>

CSS

html, body {
  margin: 0;
  height: 100%;
  width: 100%;
}

header {
  width: 100%;
  padding-bottom: 25px;
  flex-direction: column;
}

img {
  width: 70%;
}

.flex {
  display: flex;
  justify-content: center;
  align-items: center;
}

JavaScript

const imageArray = [
  "https://images.unsplash.com/photo-1508185159346-bb1c5e93ebb4?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=55cf14db6ed80a0410e229368963e9d8&auto=format&fit=crop&w=1900&q=80",
  "https://images.unsplash.com/photo-1495480393121-409eb65c7fbe?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=05ea43dbe96aba57d48b792c93752068&auto=format&fit=crop&w=1351&q=80",
  "https://images.unsplash.com/photo-1501611724492-c09bebdba1ac?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=ebdb0480ffed49bd075fd85c54dd3317&auto=format&fit=crop&w=1491&q=80",
  "https://images.unsplash.com/photo-1417106338293-88a3c25ea0be?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=d1565ecb73a2b38784db60c3b68ab3b8&auto=format&fit=crop&w=1352&q=80",
  "https://images.unsplash.com/photo-1500520198921-6d4704f98092?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=ac4bc726064d0be43ba92476ccae1a75&auto=format&fit=crop&w=1225&q=80",
  "https://images.unsplash.com/photo-1504966981333-1ac8809be1ca?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=9a1325446cbf9b56f6ee549623a50696&auto=format&fit=crop&w=1350&q=80",
  "https://images.unsplash.com/photo-1437075130536-230e17c888b5?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=ff573beba18e5bf45eb0cccaa2c862b3&auto=format&fit=crop&w=1350&q=80",
  "https://images.unsplash.com/photo-1515002246390-7bf7e8f87b54?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=1eac0f70640261e09152340f13b79144&auto=format&fit=crop&w=1350&q=80",
  "https://images.unsplash.com/photo-1506057278219-795838d4c2dd?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=f68d8d7b0223cd906ea8cac13421881d&auto=format&fit=crop&w=1350&q=80",
  "https://images.unsplash.com/photo-1488402410361-05152fa654d3?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=5266aadc96d5b5b23996e7120d3190a8&auto=format&fit=crop&w=1350&q=80",
  "https://images.unsplash.com/photo-1475598322381-f1b499717dda?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=cb49f991ce8dd947b45ccd1bd905ec8c&auto=format&fit=crop&w=1355&q=80",
  "https://images.unsplash.com/photo-1501949997128-2fdb9f6428f1?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=951ee200e732c9b8c4ea0a7372ca9d27&auto=format&fit=crop&w=1350&q=80",
  "https://images.unsplash.com/photo-1494783367193-149034c05e8f?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=a98c0f9a6c602e964e6533de413d59ba&auto=format&fit=crop&w=1350&q=80",
  "https://images.unsplash.com/photo-1476547362848-ed2a9f99cd29?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=5b4647c9e25267c25866936c916e4aa8&auto=format&fit=crop&w=1350&q=80",
  "https://images.unsplash.com/photo-1506017669510-0bcbe8003d70?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=9403f5d4ac23a5726bfc3c8308b31c01&auto=format&fit=crop&w=1350&q=80",
  "https://images.unsplash.com/photo-1489447068241-b3490214e879?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=a85cb0d68de38ae2aa00d8a9663a320a&auto=format&fit=crop&w=1350&q=80"
];
const image = document.querySelector("img");
const button = document.querySelector("button");
window.onload = () => generateRandomPicture(imageArray);
button.addEventListener("click", () => generateRandomPicture(imageArray));

function generateRandomPicture(array){
  let randomNum = Math.floor(Math.random() * array.length); 
  image.setAttribute("src", array[randomNum]);
}

图像存储在一个数组中。通过array.length生成一个数字并乘以数组中的图像数量。然后,将Math.floor将值四舍五入为整数,并在加载页面或单击按钮时在HTML中设置图像src

随机背景颜色

Pug

#app.wrap
  .bg
  .colors()
    button.refresh(v-on:click="newColors").
      
    button.expand(v-on:click="newColors").
      
    color(v-for="(c, i) in colors", v-bind:name="names[i]" v-bind:color="c")

a.fulllink(href="https://farbvelo.elastiq.ch/", target="_blank")
  strong
    span F
    span u
    span l
    span l 
    span
    span V
    span e
    span r
    span s
    span i
    span o
    span n 

SCSS

@import url('https://fonts.googleapis.com/css?family=Space+Mono');

button {
  border: none;
  margin: 0;
  padding: 0;
  width: auto;
  overflow: visible;

  background: transparent;

  /* inherit font & color from ancestor */
  color: inherit;
  font: inherit;

  /* Normalize `line-height`. Cannot be changed from `normal` in Firefox 4+. */
  line-height: normal;

  /* Corrects font smoothing for webkit */
  -webkit-font-smoothing: inherit;
  -moz-osx-font-smoothing: inherit;

  /* Corrects inability to style clickable `input` types in iOS */
  -webkit-appearance: none;
}

html {
  font-size: calc(.75rem + 1.15vh);
  font-family: 'Space Mono', monospace;
}

body {
  height: 100vh;
  background: #212121;
  overflow: hidden;
}

input {
  position: absolute;
  z-index: 2;
}

.wrap, .bg {
  position: absolute;
  top: 0; left: 0; bottom: 0; right: 0;
}

.bg {
  //opacity: .9;
  //clip-path: inset(12vmin 26% 12vmin 26%);
}

.colors {
  position: absolute;
  left: 50%;
  bottom: 10vmin; top: 10vmin;
  display: flex;
  flex-direction: column;
  cursor: pointer;

  transform: translateX(-50%);
  width: 52%;
  @media (max-width: 700px){
    width: 75%;
  }
}

.colors .color {
  position: relative;
  display: flex;
  @media (max-width: 700px){
    display: block;
    padding: 1rem;
  }
  align-items: center;
  padding: 0 1rem;
  flex-grow: 1;

  &::after {
    opacity: .5;
    content: '';
    position: absolute;
    left: 0; right: 0; bottom: 0; top: 0;
    box-shadow: 0 0 10rem currentColor;
  }
  /*
  border: solid currentColor;
  border-width: 0 2px;
  */
  transition: 200ms color linear, 200ms background-color linear, 300ms padding-bottom cubic-bezier(.7, .3, .3, 1) 100ms;
  min-height: 0.1vmax;
  
  &:last-child {
    padding-bottom: #{1.61803 * 4rem};
  }
  &:hover {
    padding-bottom: #{1.61803 * 4rem};
  }
}

.colors:hover .color {
  &:last-child {
    padding-bottom: 1rem;
  }
  &:hover {
    padding-bottom: #{1.61803 * 4rem};
  }
}

.label {
  flex-grow: 1;
  padding-right: 1rem;
  font-size: .75em;
  @media (max-width: 700px) { 
    font-size: .6em;
    margin-bottom: .15em;
  }
}
.name {
  font-size: .8em;
  text-align: right;
  @media (max-width: 700px){
    text-align: left;
  }
}
.refresh, .expand {
  z-index: 1;
  position: absolute;
  top: 100%; left: 100%;
  margin: 0;
  padding: 0;
  transform: translate(-60%,-60%);
  font-size: 2em;
  width: 1.2em; height: 1.2em;
  background: #000;
  color: #fff;
  
  border-radius: 50%;
  outline: 0;
  box-shadow: 0 0 2rem rgba(#000, .2);
  cursor: pointer;
  svg {
    position: absolute;
    top: 50%; left: 50%;
    transform: translate(-50%,-50%);
    animation-name: rotate; 
    animation-duration: 3s; 
    width: .6em; height: .6em;
    animation-iteration-count: infinite;
    animation-timing-function: linear;
    animation-play-state: paused;
    line-height: 1;
    fill: #fff;
  }
  &:hover {
    svg {
      animation-play-state: running;
    }
  }
}

.expand {
  display: none;
  margin-left: -1.4em;
  svg {
    fill: none;
    stroke: #fff;
    stroke-width: 1.5;
    animation: none;
    width: .75em; height: .75em;
  }
}

@keyframes rotate {
  from {transform: translate(-50%,-50%) rotate(0deg);}
  to {transform: translate(-50%,-50%) rotate(360deg);}
}

.fulllink {
  position: fixed;
  top: 0;
  right: 0;
  font-size: .65em;
  text-decoration: none;
  padding: 1.2em 3.5em;
  width: 10ex;
  text-align: center;
  transform: translateX(30%) rotate(45deg);
  
  span {
    position: relative;
    animation: .5s ease-in 1s infinite alternate jumpup;
    animation-duration: 1s;
    
    @for $i from 1 through 20 {
      &:nth-child(#{$i}) {
        animation-delay: 1000ms + $i * 100ms;
      }
    }
  }
}

@keyframes jumpup {
  100% {
    opacity: .1;
  }
}

Babel

// full version: https://farbvelo.elastiq.ch/
// color-names: https://github.com/meodai/color-nameshttps://github.com/meodai/color-names

const shuffleArray = arr => arr
  .map(a => [Math.random(), a])
  .sort((a, b) => a[0] - b[0])
  .map(a => a[1]);

const random = (min, max) => {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

var generateRandomColors = (total, mode = 'lab', padding = .175, parts = 4) => {
  
  let colors = [];
  const part = Math.floor(total / parts);
  const reminder = total % parts;

  // hues to pick from
  const baseHue = random(0, 360);
  const hues = [0, 60, 120, 180, 240, 300].map(offset => {
    return (baseHue + offset) % 360;
  });

  //  low saturated color
  const baseSaturation = random(5, 40);
  const baseLightness = random(0, 20);
  const rangeLightness = 90 - baseLightness;

  colors.push( HUSL.toHex(
    hues[0],
    baseSaturation,
    baseLightness * random(.25, .75)
  ) );

  for (let i = 0; i < (part - 1); i++) {
    colors.push( HUSL.toHex(
      hues[0],
      baseSaturation,
      baseLightness + (rangeLightness * Math.pow(i/(part - 1), 1.5))
    ) );
  }

  // random shades
  const minSat = random(50, 70);
  const maxSat = minSat + 30;
  const minLight = random(45, 80);
  const maxLight = Math.min(minLight + 40, 95);

  for (let i = 0; i < (part + reminder - 1); i++) {
    colors.push( HUSL.toHex(
      hues[random(0, hues.length - 1)],
      random(minSat, maxSat),
      random(minLight, maxLight) 
    ) )
  }
  
  colors.push( HUSL.toHex(
    hues[0],
    baseSaturation,
    rangeLightness
  ) );
  
  //colors = shuffleArray(colors);
  
  return chroma.scale(colors).padding(padding).mode(mode).colors(total);
}

function getContrastColor(color) {
  let currentColor = chroma( color );
  let lum = currentColor.luminance();
  let contrastColor;
  if ( lum < 0.15 ) {
    contrastColor = currentColor.set('hsl.l', '+.25');  
  } else {
    contrastColor = currentColor.set('hsl.l', '-.35');
  }
  return contrastColor;
}

Vue.component('color', {
  props: ['color', 'name'],
  template: `
{{ color }}
{{ name.name }}
`
, computed: { /*name: function () { console.log(name) return getClosestNamedColor( this.color ).name; },*/ textColor: function () { return getContrastColor(this.color); } } }); let colors = new Vue({ el: '#app', data: () => { return { colors: [], names: [], amount: 6, } }, methods: { getNames: function () { fetch(`https://api.color.pizza/v1/${this.colors.join().replace(/#/g, '')}?noduplicates=true&goodnamesonly=true`) .then(data => data.json()) .then(data => { this.names = data.colors; }); }, newColors: function () { let colorArr = generateRandomColors(this.amount) this.colors = colorArr; this.getNames(); let gradient = [...colorArr]; gradient[0] += ' 12vmin' gradient[gradient.length - 1] += ' 69%' //url("https://www.transparenttextures.com/patterns/concrete-wall.png"), document.querySelector('.bg').style['background-image'] = ` linear-gradient(to bottom, ${gradient.join(',')}) `; document.querySelector('.refresh').style.background = this.colors[this.colors.length - 1]; document.querySelector('.expand').style.background = this.colors[this.colors.length - 1]; document.querySelector('.fulllink').style.background = this.colors[1]; document.querySelector('.fulllink').style.color = getContrastColor(this.colors[1]); } }, mounted: function () { this.newColors(); } });

这就是奇迹发生的地方:

const random = (min, max) => {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

代码的第一行随机打乱数组,第二行返回0到10之间的随机数字。在随机颜色背景的示例中,可以设置颜色和特定范围,例如色相,饱和度和阴影。

有关生成随机十六进制颜色的另一种方法,请查看Chris Coyer的这篇文章

艺术效果

HTML

<html lang="en">
<head>
<meta charset="UTF-8">
<title>HTML5 Canvas Generative Arttitle>
<style type="text/css">  
style>
head>
<body>
<div id="container"> 
    <canvas id="displayCanvas" width="1024px" height="576px">
        Your browser does not support HTML5 canvas.
    canvas>
    <form>
    <p id="caption">
        HTML5 Canvas - Morphing Fractal Curves, version 2.
        
      
        <br><a href="http://www.rectangleworld.com">rectangleworld.coma>
    p>
    form>
div>
body>
html>

CSS

body {background-color:#000000; color:#333333;} 
  h4 {font-family: sans-serif; color:#333333; font-size:16px;}
  h3 {font-family: sans-serif; color:#333333;}
  p {font-family: sans-serif; color:#333333; font-size:14px;}
    #caption {position:absolute; width:1024px; text-align:center; top:520px; z-index:1}
  a {font-family: sans-serif; color:#d15423; text-decoration:none;}
  canvas {}
    #displayCanvas {position:absolute; top:10px; z-index:0;}
  div {}
    #container {width:1024px; height:576px; margin:auto;}

JavaScript

indow.addEventListener("load", windowLoadHandler, false);

//for debug messages while testing code
var Debugger = function() { };
Debugger.log = function(message) {
  try {
    console.log(message);
  }
  catch (exception) {
    return;
  }
}

function windowLoadHandler() {
  canvasApp();
}

function canvasSupport() {
  return Modernizr.canvas;
}

function canvasApp() {
  if (!canvasSupport()) {
    return;
  }
  
  var displayCanvas = document.getElementById("displayCanvas");
  var context = displayCanvas.getContext("2d");
  var displayWidth = displayCanvas.width;
  var displayHeight = displayCanvas.height;
  
  //off screen canvas used only when exporting image
  var exportCanvas = document.createElement('canvas');
  exportCanvas.width = displayWidth;
  exportCanvas.height = displayHeight;
  var exportCanvasContext = exportCanvas.getContext("2d");
  
  //var exportImage = document.createElement('img');
  
  //buttons
  var btnExport = document.getElementById("btnExport");
  btnExport.addEventListener("click", exportPressed, false);
  
  var btnRegenerate = document.getElementById("btnRegenerate");
  btnRegenerate.addEventListener("click", regeneratePressed, false);
  
  var numCircles;
  var maxMaxRad;
  var minMaxRad;
  var minRadFactor;
  var circles;
  var iterations;
  var numPoints;
  var timer;
  var drawsPerFrame;
  var drawCount;
  var bgColor,urlColor;
  var lineWidth;
  var colorParamArray;
  var colorArray;
  var dataLists;
  var minX, maxX, minY, maxY;
  var xSpace, ySpace;
  var lineNumber;
  var twistAmount;
  var fullTurn;
  var lineAlpha;
  var maxColorValue;
  var minColorValue;
  
  init();
  
  function init() {
    numCircles = 15; //35
    maxMaxRad = 200;
    minMaxRad = 200;
    minRadFactor = 0;
    iterations = 11;
    numPoints = Math.pow(2,iterations)+1;
    drawsPerFrame = 4;
    
    fullTurn = Math.PI*2*numPoints/(1+numPoints);
    
    minX = -maxMaxRad;
    maxX = displayWidth + maxMaxRad;
    minY = displayHeight/2-50;
    maxY = displayHeight/2+50;
    
    twistAmount = 0.67*Math.PI*2;
    
    stepsPerSegment = Math.floor(800/numCircles);
    
    maxColorValue = 100;
    minColorValue = 20;
    lineAlpha = 0.10;
    
    bgColor = "#000000";
    urlColor = "#333333";
    
    lineWidth = 1.01;
    
    startGenerate();
  }
    
  function startGenerate() {
    drawCount = 0;
    context.setTransform(1,0,0,1,0,0);
    
    context.clearRect(0,0,displayWidth,displayHeight);
    
    setCircles();
    
    colorArray = setColorList(iterations);
        
    lineNumber = 0;
    
    if(timer) {clearInterval(timer);}
    timer = setInterval(onTimer,1000/60);
    
  }
  
  function setColorList(iter) {
    var r0,g0,b0;
    var r1,g1,b1;
    var r2,g2,b2;
    var param;
    var colorArray;
    var lastColorObject;
    var i, len;
    
    var maxComponentDistance = 32;
    var maxComponentFactor = 0.5;
    
    
    r0 = minColorValue + Math.random()*(maxColorValue-minColorValue);
    g0 = minColorValue + Math.random()*(maxColorValue-minColorValue);
    b0 = minColorValue + Math.random()*(maxColorValue-minColorValue);;
    
    r1 = minColorValue + Math.random()*(maxColorValue-minColorValue);
    g1 = minColorValue + Math.random()*(maxColorValue-minColorValue);
    b1 = minColorValue + Math.random()*(maxColorValue-minColorValue);
    
    
    /*
    //can also set colors explicitly here if you like.
    r1 = 90;
    g1 = 60;
    b1 = 20;
    
    r0 = 30;
    g0 = 77;
    b0 = 66;
    */
    
    a = lineAlpha;
    
    var colorParamArray = setLinePoints(iter);
    colorArray = [];
    
    len = colorParamArray.length;
    
    for (i = 0; i < len; i++) {
      param = colorParamArray[i];
      
      r = Math.floor(r0 + param*(r1 - r0));
      g = Math.floor(g0 + param*(g1 - g0));
      b = Math.floor(b0 + param*(b1 - b0));
        
      var newColor = "rgba("+r+","+g+","+b+","+a+")";
      
      colorArray.push(newColor);
    }
    
    return colorArray;
    
  }
  
  function setCircles() {
    var i;
    var r,g,b,a;
    var grad;
    
    circles = [];
    
    for (i = 0; i < numCircles; i++) {
      maxR = minMaxRad+Math.random()*(maxMaxRad-minMaxRad);
      minR = minRadFactor*maxR;
      
      var newCircle = {
        centerX: minX + i/(numCircles-1)*(maxX - minX),
        centerY: minY + i/(numCircles-1)*(maxY - minY),
        //centerY: minY + Math.random()*(maxY - minY),
        maxRad : maxR,
        minRad : minR,
        phase : i/(numCircles-1)*twistAmount,
        pointArray : setLinePoints(iterations)
        };
      circles.push(newCircle);
    }
  }
  
  function onTimer() {
    var i;
    var cosTheta, sinTheta;
    var theta;
    
    var numCircles = circles.length;

    var linParam;
    var cosParam;
    var centerX, centerY;
    var xSqueeze = 0.75;
    var x0,y0;
    var rad, rad0, rad1;
    var phase, phase0, phase1;
    
    for (var k = 0; k < drawsPerFrame; k++) {
    
      theta = lineNumber/(numPoints-1)*fullTurn;
      
      context.globalCompositeOperation = "lighter";
      
      context.lineJoin = "miter";
      
      context.strokeStyle = colorArray[lineNumber];
      context.lineWidth = lineWidth;
      context.beginPath();
      
      //move to first point
      centerX = circles[0].centerX;
      centerY = circles[0].centerY;
      rad = circles[0].minRad + circles[0].pointArray[lineNumber]*(circles[0].maxRad - circles[0].minRad);
      phase = circles[0].phase;
      x0 = centerX + xSqueeze*rad*Math.cos(theta + phase);
      y0 = centerY + rad*Math.sin(theta + phase);
      context.moveTo(x0,y0);
      
      for (i=0; i< numCircles-1; i++) {
        //draw between i and i+1 circle
        rad0 = circles[i].minRad + circles[i].pointArray[lineNumber]*(circles[i].maxRad - circles[i].minRad);
        rad1 = circles[i+1].minRad + circles[i+1].pointArray[lineNumber]*(circles[i+1].maxRad - circles[i+1].minRad);
        phase0 = circles[i].phase;
        phase1 = circles[i+1].phase;
        
        for (j = 0; j < stepsPerSegment; j++) {
          linParam = j/(stepsPerSegment-1);
          cosParam = 0.5-0.5*Math.cos(linParam*Math.PI);
          
          //interpolate center
          centerX = circles[i].centerX + linParam*(circles[i+1].centerX - circles[i].centerX);
          centerY = circles[i].centerY + cosParam*(circles[i+1].centerY - circles[i].centerY);
          
          //interpolate radius
          rad = rad0 + cosParam*(rad1 - rad0);
          
          //interpolate phase
          phase = phase0 + cosParam*(phase1 - phase0);
          
          x0 = centerX + xSqueeze*rad*Math.cos(theta + phase);
          y0 = centerY + rad*Math.sin(theta + phase);
          
          context.lineTo(x0,y0);
          
        }
        
      }
      
      context.stroke();
          
      lineNumber++;
      if (lineNumber > numPoints-1) {
        clearInterval(timer);
        timer = null;
        break;
      }
    }
  }
    
  //Here is the function that defines a noisy (but not wildly varying) data set which we will use to draw the curves.
  //We first define the points in a linked list, but then store the values in an array.
  function setLinePoints(iterations) {
    var pointList = {};
    var pointArray = [];
    pointList.first = {x:0, y:1};
    var lastPoint = {x:1, y:1}
    var minY = 1;
    var maxY = 1;
    var point;
    var nextPoint;
    var dx, newX, newY;
    var ratio;
    
    var minRatio = 0.5;
        
    pointList.first.next = lastPoint;
    for (var i = 0; i < iterations; i++) {
      point = pointList.first;
      while (point.next != null) {
        nextPoint = point.next;
        
        dx = nextPoint.x - point.x;
        newX = 0.5*(point.x + nextPoint.x);
        newY = 0.5*(point.y + nextPoint.y);
        newY += dx*(Math.random()*2 - 1);
        
        var newPoint = {x:newX, y:newY};
        
        //min, max
        if (newY < minY) {
          minY = newY;
        }
        else if (newY > maxY) {
          maxY = newY;
        }
        
        //put between points
        newPoint.next = nextPoint;
        point.next = newPoint;
        
        point = nextPoint;
      }
    }
    
    //normalize to values between 0 and 1
    //Also store y values in array here.
    if (maxY != minY) {
      var normalizeRate = 1/(maxY - minY);
      point = pointList.first;
      while (point != null) {
        point.y = normalizeRate*(point.y - minY);
        pointArray.push(point.y);
        point = point.next;
      }
    }
    //unlikely that max = min, but could happen if using zero iterations. In this case, set all points equal to 1.
    else {
      point = pointList.first;
      while (point != null) {
        point.y = 1;
        pointArray.push(point.y);
        point = point.next;
      }
    }
        
    return pointArray;    
  }
    
  function exportPressed(evt) {
    //background - otherwise background will be transparent.
    exportCanvasContext.fillStyle = bgColor;
    exportCanvasContext.fillRect(0,0,displayWidth,displayHeight);
    
    //draw
    exportCanvasContext.drawImage(displayCanvas, 0,0,displayWidth,displayHeight,0,0,displayWidth,displayHeight);
    
    //add printed url to image
    exportCanvasContext.fillStyle = urlColor;
    exportCanvasContext.font = 'bold italic 16px Helvetica, Arial, sans-serif';
    exportCanvasContext.textBaseline = "top";
    var metrics = exportCanvasContext.measureText("rectangleworld.com");
    exportCanvasContext.fillText("rectangleworld.com", displayWidth - metrics.width - 10, 5);
    
    //we will open a new window with the image contained within:    
    //retrieve canvas image as data URL:
    var dataURL = exportCanvas.toDataURL("image/png");
    //open a new window of appropriate size to hold the image:
    var imageWindow = window.open("", "fractalLineImage", "left=0,top=0,width="+displayWidth+",height="+displayHeight+",toolbar=0,resizable=0");
    //write some html into the new window, creating an empty image:
    imageWindow.document.write("Export Image")
    imageWindow.document.write("
                  + " alt=''"
                  + " height='" + displayHeight + "'"
                  + " width='"  + displayWidth  + "'"
                  + " style='position:absolute;left:0;top:0'/>");
    imageWindow.document.close();
    //copy the image into the empty img in the newly opened window:
    var exportImage = imageWindow.document.getElementById("exportImage");
    exportImage.src = dataURL;
  }
  
  function regeneratePressed(evt) {
    startGenerate();
  }
  
}

在此变形分形曲线中,Math.random两次用于设置渐变的颜色,一次用于设置曲线的最大半径。 这是在每次迭代中构建全新外观的好方法!

文字效果

Slim

h1
  svg role="img"
    title.title Random Words!    

    text.word x="50%" y="50%" text-anchor="middle" fill="#222" stroke="#222" stroke-width="1.5%" dominant-baseline="central" stroke-linecap="round" Random Words!

    text.word x="50%" y="50%" text-anchor="middle" fill="white" dominant-baseline="central" Random Words!

p Made with <b>b> by <a href="https://twitter.com/LandonSchropp">Landon Schroppa>

Sass

html, body, h1
  
  height: 100%
  width: 100%

body
  transition: background-color 0.3s ease-in
  font-family: 'Open Sans', sans-serif
  background-color: hsl(350, 100%, 50%)
  
  // in firefox, a transformed element causes a scroll when it extends beyond the element's size, so we'll disable it
  overflow: hidden
  
  font-size: 12px
  
  @media (min-width: 480px)
    font-size: 14px
  
  @media (min-width: 640px)
    font-size: 16px
  
.word
  font-family: 'Bangers', cursive
  
svg
  height: 100%
  width: 100%
  position: relative
  top: -1rem
  animation: pop-out 2s ease-in-out infinite
    
.word
  font-family: 'Bangers', cursive
  letter-spacing: 0.05em
  color: white
  padding: 0.5em

  font-size: 28px

  @media (min-width: 480px)
    font-size: 36px

  @media (min-width: 640px)
    font-size: 48px

  @media (min-width: 960px)
    font-size: 64px

  @media (min-width: 1280px)
    font-size: 84px
  
p
  position: fixed
  bottom: 0
  left: 0
  right: 0
  line-height: 2rem
    
  text-align: center
  color: transparentize(white, 0.25)
  background-color: transparentize(#222, 0.0)

@keyframes pop-out
  0%
    transform: scale3d(0, 0, 1)
    opacity: 1
  25%
    transform: scale3d(1, 1, 1)
    opacity: 1
  100%
    transform: scale3d(1.5, 1.5, 1)
    opacity: 0
  
a, a:visited
  color: inherit
V

JavaScript

$(document).ready(function () {
  // set the background to a random color
  var hue = 350;

  // cache the jquery elements to prevent dom queries during the animation events
  var $body = $("body");
  var $svg = $("svg");
  var $word = $(".word");

  // when the animation iterates
  $("h1").on(
    "webkitAnimationIteration oanimationiteration msAnimationIteration animationiteration ",
    function () {
      // replace the header with a random word
      var word = words[Math.floor(Math.random() * words.length)] + "!";
      $word.text(word);

      // update the background color
      hue += 47;
      $body.css("background-color", "hsl(" + hue + ", 100%, 50%)");
    }
  );
});

// the 10,000 most comment words, taken from https://goo.gl/hfjFkz
words = [
  "the",
  "of",
  "and",
   ];

我们使用Math.random将标题替换为数组中随机选择的单词:

var word = words[Math.floor(Math.random() * words.length)] + "!";

这很像随机图像示例-对于初学者来说是一种完美的练习!

API密钥生成器

HTML

<div class="wrapper">
  
  <button class="form-control" id="keygen">Generate API Keybutton>
  
  <input class="form-control" id="apikey" type="text" value="" placeholder="Click on the button to generate a new API key ..."  />
  
div>

CSS

body {
  text-align: center;
  background: #f1f1f1;
}

.wrapper {
  padding-top:60px;
}

button.form-control {
  background: #f7f7f7 none repeat scroll 0 0;
  border-color: #ccc;
  box-shadow: 0 1px 0 #ccc;
  color: #555;
  vertical-align: top;
  border-radius: 3px;
  border-style: solid;
  border-width: 1px;
  box-sizing: border-box;
  cursor: pointer;
  display: inline-block;
  font-size: 13px;
  height: 28px;
  line-height: 26px;
  margin: 0;
  padding: 0 10px 1px;
  text-decoration: none;
  white-space: nowrap;
}

input.form-control {
  background-color: #fff;
  border: 1px solid #ddd;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07) inset;
  color: #32373c;
  outline: 0 none;
  transition: border-color 50ms ease-in-out 0s;
  margin: 1px;
  padding: 3px 5px;
  border-radius: 0;
  font-size: 14px;
  font-family: inherit;
  font-weight: inherit;
  box-sizing: border-box;
  color: #444;
  font-family: "Open Sans",sans-serif;
  line-height: 1.4em;
  width: 310px;
}

JavaScript

function generateUUID()
{
  var d = new Date().getTime();
  
  if( window.performance && typeof window.performance.now === "function" )
  {
    d += performance.now();
  }  
  var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c)
  {
    var r = (d + Math.random()*16)%16 | 0;
    d = Math.floor(d/16);
    return (c=='x' ? r : (r&0x3|0x8)).toString(16);
  });

return uuid;
}

/**
 * Generate new key and insert into input value
 */
$( '#keygen' ).on('click',function(){
  $( '#apikey' ).val( generateUUID() );
});

这是一个随机数的超级现实应用案例! 该演示会生成16个随机数,以创建一个通用唯一标识符(UUID),该标识符可用作提供对API的访问的密钥。

打乱文本

HTML

<div class="container">
  <div class="text">div>
div>

Stylus

@import 'https://fonts.googleapis.com/css?family=Roboto+Mono:100'
html, body
  font-family 'Roboto Mono', monospace
  background #212121
  height 100%
.container
  height 100%
  width 100%
  justify-content center
  align-items center
  display flex
.text
  font-weight 100
  font-size 28px
  color #FAFAFA
.dud
  color #757575

Babel

class TextScramble {
  constructor(el) {
    this.el = el
    this.chars = '!<>-_\\/[]{}—=+*^?#________'
    this.update = this.update.bind(this)
  }
  setText(newText) {
    const oldText = this.el.innerText
    const length = Math.max(oldText.length, newText.length)
    const promise = new Promise((resolve) => this.resolve = resolve)
    this.queue = []
    for (let i = 0; i < length; i++) {
      const from = oldText[i] || ''
      const to = newText[i] || ''
      const start = Math.floor(Math.random() * 40)
      const end = start + Math.floor(Math.random() * 40)
      this.queue.push({ from, to, start, end })
    }
    cancelAnimationFrame(this.frameRequest)
    this.frame = 0
    this.update()
    return promise
  }
  update() {
    let output = ''
    let complete = 0
    for (let i = 0, n = this.queue.length; i < n; i++) {
      let { from, to, start, end, char } = this.queue[i]
      if (this.frame >= end) {
        complete++
        output += to
      } else if (this.frame >= start) {
        if (!char || Math.random() < 0.28) {
          char = this.randomChar()
          this.queue[i].char = char
        }
        output += `${char}`
      } else {
        output += from
      }
    }
    this.el.innerHTML = output
    if (complete === this.queue.length) {
      this.resolve()
    } else {
      this.frameRequest = requestAnimationFrame(this.update)
      this.frame++
    }
  }
  randomChar() {
    return this.chars[Math.floor(Math.random() * this.chars.length)]
  }
}

// ——————————————————————————————————————————————————
// Example
// ——————————————————————————————————————————————————

const phrases = [
  'Neo,',
  'sooner or later',
  'you\'re going to realize',
  'just as I did',
  'that there\'s a difference',
  'between knowing the path',
  'and walking the path'
]

const el = document.querySelector('.text')
const fx = new TextScramble(el)

let counter = 0
const next = () => {
  fx.setText(phrases[counter]).then(() => {
    setTimeout(next, 800)
  })
  counter = (counter + 1) % phrases.length
}

next()

依次存储和显示一些短语,并由一个动画隔开,该动画看起来像是用Math.random选择的短语之间的随机字符来扰乱字母。

石头剪刀布

HTML

<ul id="moves">
  <li data-move="rock">
    <span class="fa fa-fw fa-hand-rock-o">span>
    <span class="text">Rockspan>
  li>
  <li data-move="paper">
    <span class="fa fa-fw fa-hand-paper-o">span>
    <span class="text">Paperspan>
  li>
  <li data-move="scissors">
    <span class="fa fa-fw fa-hand-scissors-o">span>
    <span class="text">Scissorsspan>
  li>
ul>
<div class="scoreboard">
  <table>
    <thead>
      <td>Playertd>
      <td>Computertd>
    thead>
    <tbody>
      <tr>
        <td class="Player-count">0td>
        <td class="Computer-count">0td>
      tr>
    tbody>
  table>
div>

SCSS

// Observify Colours
$light-blue: #edf0f9;
$dark-blue: #151e28;
$blue: #019cdf;
$green: #35b197;
$red: #e94d5a;
$orange: #f66e3a;
$pink: #f583b6;
$purple: #7e4894;
$black: #000000;
$white: #ffffff;

// Variables
$body-bg: $dark-blue;
$color: $light-blue;
$font: 'Open Sans', sans-serif;
$font-size: 16px;

@keyframes icon-animation {
  0% { transform: scale(1); opacity: 1; }
  50% { transform: scale(1.4); }
  60% { opacity: 0;} 
  80% { transform: scale(0.5); }
  90% { opacity: 0; }
}

body {
  background-color: $body-bg;
  color: $color;
  font-family: $font;
  font-size: $font-size;
}

// Put your prototype code here
#moves {
  list-style: none;
  width: 100%;
  padding: 0;
  display: flex;
  
  li {
    background: $green;
    width: 33.33%;
    margin: 1em;
    
    &:hover {
      background: lighten($green, 10);
    }

    &:active {
      background: $orange;
    }
    
    .fa {
      display: block;
      font-size: 48px;
      text-align: center;
      width: 100%;
      padding: 1em;
      box-sizing: border-box;
      
      &.animating {
        animation: icon-animation 2s 1;
      }
    }

    .text {
      text-align: center;
      width: 100%;
      display: block;
      padding-bottom: 2em;
      text-transform: uppercase;
      letter-spacing: 0.2em;
      font-weight: 600;
      font-size: 11px;
    }
  }
}

.scoreboard {
  width: 100%;
  
  table {
    width: 100%;
    background: lighten($body-bg, 3);
    
    td {
      padding: .5em;
      box-sizing: border-box;
      text-align: center;
      text-transform: uppercase;
    }

    thead {
      font-size: 12px;
      font-weight: 700;
      letter-spacing: 0.2em;
      
      td {
        padding-top: 2em;
      }
    }

    tbody {
      td {
        font-size: 96px;
        font-weight: 900;
        line-height: 1em;
      }
    }
  }
}

JavaScript

$(window).load(function() {
  
  var movesContainer = $('#moves'),
      playerCount = $('.Player-count'),
      computerCount = $('.Computer-count');
  
  $('#moves li').on("click", function() {
    var yourMove = $(this).data('move');
    processMoves(yourMove);
    
    var icon = $(this).find('.fa');
    icon.addClass('animating');
    
    var s = setTimeout(function(icon) {
      $('#moves li .fa').removeClass('animating');
      clearTimeout();
    }, 5000);
  });
  
});

function processMoves(yourMove) {
  var opponentMove = generateRandomOpponentMove();
  calculateWinner(yourMove,opponentMove);
}

function generateRandomOpponentMove() {
  var availableMoves = ['rock','paper','scissors'],
      randomNumber = Math.floor(Math.random() * availableMoves.length),
      opponentMove = availableMoves[randomNumber];
  
  return opponentMove;
}

function calculateWinner(yourMove, opponentMove) {
  switch(yourMove) {
    case 'rock':
      if(opponentMove === 'rock') {
        return 'draw';
      } else if (opponentMove === 'scissors') {
        youWin();
      } else {
        youLose();
      }
      break;
    case 'paper':
      if(opponentMove === 'paper') {
        return 'draw';
      } else if (opponentMove === 'rock') {
        youWin();
      } else {
        youLose();
      }
      break;
    case 'scissors':
      if(opponentMove === 'scissors') {
        return 'draw';
      } else if (opponentMove === 'paper') {
        youWin();
      } else {
        youLose();
      }
      break;
  }
}

function youWin() {
  var playerScore = $('.Player-count');
  var playerScoreUpdated = parseInt(playerScore.text()) + 1;
  playerScore.text(playerScoreUpdated);
}

function youLose() {
  var computerScore = $('.Computer-count');
  var computerScoreUpdated = parseInt(computerScore.text()) + 1;
  computerScore.text(computerScoreUpdated);
}

在这个童年时代的经典剪刀石头布游戏中,Math.random作为对手的计算机生成随机移动。 它从三个可用的招式中进行选择。

密码生成器

HTML

div id="app">
    <section class="wrapper">   
      <h1>The Password Genieh1>
      <div class="password-box">
        <span id="password" class="password" v-on:click="copyToClipboard">{{ password }}span>
        <span class="regenerate-password" v-on:click="generatePassword">span>
        <span class="copy-password" v-on:click="copyToClipboard">span>
        <span class="tooltip" v-if="copied">Password copied successfuly!span>
      div>
      <form @keydown.enter.prevent="">
        <div class="field-wrap">
          <label>Strengthlabel>
          <span class="range-value">{{strength.text}}span>
          <div class="range-slider_wrapper slider-strength" v-bind:class="strength.text">
            <span class="slider-bar" v-bind:style="{ width: strength.score + '%' }">span>
            <input type="range" class="range-slider" min="0" max="100" v-model="strength.score" disabled>
          div>  
        div>
        <div class="seperator">div>
        <div class="field-wrap">
          <label>Lengthlabel>
          <span class="range-value">{{settings.length}}span>
          <div class="range-slider_wrapper">
            <span class="slider-bar" v-bind:style="{ width: lengthThumbPosition + '%' }">span>
            <input type="range" class="range-slider" min="6" v-bind:max="settings.maxLength" v-model="settings.length">
          div>  
        div>
        <div class="field-wrap">  
          <label>Digitslabel>
          <span class="range-value">{{settings.digits}}span>
          <div class="range-slider_wrapper">
            <span class="slider-bar"  v-bind:style="{ width: digitsThumbPosition + '%' }">span>
            <input type="range" class="range-slider" min="0" v-bind:max="settings.maxDigits" v-model="settings.digits">
          div>  
        div>
        <div class="field-wrap">  
          <label>Symbolslabel>
          <span class="range-value">{{settings.symbols}}span>
          <div class="range-slider_wrapper">
            <span class="slider-bar"  v-bind:style="{ width: symbolsThumbPosition + '%' }">span>
            <input type="range" class="range-slider" min="0" v-bind:max="settings.maxSymbols" v-model="settings.symbols">
          div>  
        div>
      form>
    section>
  div>

SCSS

$blue: #3fa4f4;
$purple: #6e77f7;
$peach: #fc8680;
$pink: #ef5081;
$green: #8BC34A;
$dark-green: #4caf50;
$red: #ff6666;
$orange: #ff9800;

$wrapper-bg: #f4f7fc;
$wrapper-width: 400px;

*{
  box-sizing: border-box;
}

body{
  font-size: 15px;
  font-family: Tahoma,Verdana,Segoe,sans-serif;
  color: #444;
  background-color: #fefefe;
  background-image:  linear-gradient(-45deg, #018bfd 0%, #3F51B5 100%);
  background-repeat: no-repeat;
  background-size: cover;
  padding: 0 20px;
  margin: 0;
  min-height: 100vh;
  position: relative;
}

.header{
  padding: 2em 0;
  text-align: center;

  .title{
    font-size: 1.2em;
    font-weight: bold;
    color: #fff;

    img{
      width: 12px;
      margin: 0 2px 2px;
      vertical-align: bottom;
    }
  }
}

.wrapper{
  width: $wrapper-width;
  max-width: 100%;
  min-height: 400px;
  margin: 40px auto;
  position: relative;
  border: 1px solid #eee;
  border-radius: 3px;
  padding: 40px 20px;
  font-size: 0.85em;
  -webkit-box-shadow: 0 0 15px 0 rgba(0,0,0,0.05);
  box-shadow: 0 0 15px 0 rgba(0,0,0,0.05);
  background-color: $wrapper-bg;
  position: relative;
  transition: all ease-in 0.25s;
}

h1{
  text-align: center;
  margin: 0 0 40px;
}
.field-wrap{
  margin-bottom: 20px;
}

form{
  overflow: overlay;
  margin-top: 30px;
}

label{
  display: inline-block;
  min-width: 20%;
}

.range-slider_wrapper{
  position: relative;
  width: 100%;
  margin: 10px 0 30px;
}

.range-slider{
  -webkit-appearance: none;
  appearance: none;
  background: lighten($blue, 20%);
  width: 100%;
  border-radius: 3px;
  vertical-align: bottom;
  margin: 0;
  height: 6px;
  cursor: pointer;
  transition: all ease-in 0.25s;
}

.range-slider::-webkit-slider-thumb{
  -webkit-appearance: none;
  appearance: none;
  border-radius: 0;
  border: 0;
  position:relative;
  width: 4px;
  height: 15px;
  background-color: darken($blue, 5%);
}
.range-slider::-moz-range-thumb{
  -moz-appearance: none;
  appearance: none;
  border-radius: 0;
  border: 0;
  position:relative;
  width: 4px;
  height: 15px;
  background-color: darken($blue, 5%);
}

.range-slider{
  &:focus{
    outline: none;
  }

  &:hover, &:active{
    &::-webkit-slider-thumb{
      top: 0px;
    }
  }
}
::-moz-range-track {
  background: transparent;
  border: 0;
}
input::-moz-focus-inner,
input::-moz-focus-outer { 
  border: 0; 
}

.range-value{
  text-transform: capitalize;
  float: right;
  vertical-align: bottom;
  min-width: 30px;
  display: inline-block;
  text-align: center;
  border-radius: 3px;
  font-size: 0.9em;
}

.slider-bar{
  position: absolute;
  height: 6px;
  border-top-left-radius: 3px;
  border-bottom-left-radius: 3px;
  background: $blue;
  left: 0;
  bottom: 0;
  pointer-events: none;
}


.slider{
  &-strength{
    .range-slider{
      cursor: default;
    }

    .slider-bar{
      border-radius: 3px;
      transition: all ease-in 0.25s;
    }
    .range-slider::-webkit-slider-thumb{
      background-color: transparent;
    }
    .range-slider::-moz-range-thumb{
      background-color: transparent;
    }

    &.weak{
      .range-slider{
        background-color: lighten($red, 30%);
      }
      .slider-bar, .slider-bar:after{
        background-color: $red;
      }
    }

    &.average{
      .range-slider{
        background-color: lighten($orange, 30%);
      }
      .slider-bar, .slider-bar:after{
        background-color: $orange;
      }
    }

    &.strong{
      .range-slider{
        background-color: lighten($green, 30%);
      }
      .slider-bar, .slider-bar:after{
        background-color: $green;
      }
    }

    &.secure{
      .range-slider{
        background-color: lighten($green, 30%);
      }
      .slider-bar, .slider-bar:after{
        background-color: $green;
      }
    }

  }
}

.password-box{
  width: 100%;
  min-height: 80px;
  margin-bottom: 40px;
  position: relative;
  text-align: center;
  border-radius: 3px;
  background: #fff;
  letter-spacing: 2px;
  transition: all ease-in 0.3s;
  border: 1px solid rgb(189, 204, 230);

  .password{
    width: 70%;
    padding: 1.5em 1em;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    word-wrap: break-word;
  }
}

.regenerate-password, .copy-password{
  width: 44px;
  height: 50%;
  position: absolute;
  right: 0;
  transition: all ease-in 0.25s;

  &:hover{
    opacity: 0.8;
  }
}

.regenerate-password{
  top: 0;
  background-color: #fff;
  background-image: url('https://nourabusoud.github.io/password-genie/images/regenerate.svg');
  background-size: 40%;
  background-position: center center;
  background-repeat: no-repeat;
  transition: all ease-in 0.25s;
  cursor: pointer;

  &:hover{
    background-color: #fff;
  }
}

.copy-password{
  bottom: 0;
  background-color: #fff;
  background-image: url('https://nourabusoud.github.io/password-genie/images/copy-full.svg');
  background-size: 50%;
  background-position: center center;
  background-repeat: no-repeat;
  transition: all ease-in 0.25s;
  cursor: pointer;

  &:hover{
    background-color: #fff;
  }
}


.tooltip{
  font-size: 0.8em;
  display: block;
  text-align: center;
  padding: 0.5em;
  border-radius: 3px;
  position: absolute;
  bottom: -35px;
  left: 50%;
  transform: translateX(-50%);
}

.seperator{
  width: 100%;
  height: 3px;
  background-color: #fff;
  margin: 60px 0 40px;
}


/* Footer */
footer{  
  width: 100%;
  text-align: center;
  color: #fff;
}

footer a{
  color: #fff;
}

.github-links{
  margin-bottom: 30px;
}

// fix for copy text
textarea, textarea:focus{
  font-size: 16px;
}

JavaScript

new Vue({
  el: '#app',
  data() {
    return {
      password: '',
      copied: false,
      settings: {
        maxLength: 64,
        maxDigits: 10,
        maxSymbols: 10,
        length: 12,
        digits: 4,
        symbols: 2,
        ambiguous: true,
      }
    };
  },
  computed: {
    lengthThumbPosition: function() {
      return (( (this.settings.length - 6) / (this.settings.maxLength - 6)) * 100);
    },
    digitsThumbPosition: function() {
      return (( (this.settings.digits - 0) / (this.settings.maxDigits - 0)) * 100);
    },
    symbolsThumbPosition: function() {
      return (( (this.settings.symbols - 0) / (this.settings.maxSymbols - 0)) * 100);
    },
    strength: function() {
      var count = {
        excess: 0,
        upperCase: 0,
        numbers: 0,
        symbols: 0
      };


      var weight = {
        excess: 3,
        upperCase: 4,
        numbers: 5,
        symbols: 5,
        combo: 0, 
        flatLower: 0,
        flatNumber: 0
      };

      var strength = {
        text: '',
        score: 0
      };

      
      var baseScore = 30;

      for (i=0; i < this.password.length;i++){
        if (this.password.charAt(i).match(/[A-Z]/g)) {count.upperCase++;}
        if (this.password.charAt(i).match(/[0-9]/g)) {count.numbers++;}
        if (this.password.charAt(i).match(/(.*[!,@,#,$,%,^,&,*,?,_,~])/)) {count.symbols++;} 
      }
      
      count.excess = this.password.length - 6;
      
      if (count.upperCase && count.numbers && count.symbols){
        weight.combo = 25; 
      }
      else if ((count.upperCase && count.numbers) || (count.upperCase && count.symbols) || (count.numbers && count.symbols)){
        weight.combo = 15; 
      }
      
      if (this.password.match(/^[\sa-z]+$/))
      { 
        weight.flatLower = -30;
      }
      
      if (this.password.match(/^[\s0-9]+$/))
      { 
        weight.flatNumber = -50;
      }

      var score = 
        baseScore + 
        (count.excess * weight.excess) + 
        (count.upperCase * weight.upperCase) + 
        (count.numbers * weight.numbers) + 
        (count.symbols * weight.symbols) + 
        weight.combo + weight.flatLower + 
        weight.flatNumber;

      if(score < 30 ) {
        strength.text = "weak";
        strength.score = 10;
        return strength;
      } else if (score >= 30 && score < 75 ){
        strength.text = "average";
        strength.score = 40;
        return strength;
      } else if (score >= 75 && score < 150 ){
        strength.text = "strong";
        strength.score = 75;
        return strength;
      } else {
        strength.text = "secure";
        strength.score = 100;
        return strength;
      }
    },
  },
  mounted() {
    this.generatePassword();
  },
  watch: {
    settings: {
      handler: function() {
        this.generatePassword();
      },
      deep: true
    }
  },
  methods: {
    // copy password to clipboard
    copyToClipboard(){
      // we should create a textarea, put the password inside it, select it and finally copy it
      var copyElement = document.createElement("textarea");
      copyElement.style.opacity = '0';
      copyElement.style.position = 'fixed';
      copyElement.textContent = this.password;
      var body = document.getElementsByTagName('body')[0];
      body.appendChild(copyElement);
      copyElement.select();
      document.execCommand('copy');
      body.removeChild(copyElement);
      
      this.copied = true;
      // reset this.copied
      setTimeout(() => {
        this.copied = false;
      }, 750);
    },
    // generate the password
    generatePassword() {
      var lettersSetArray = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"];
      var symbolsSetArray = [ "=","+","-","^","?","!","%","&","*","$","#","^","@","|"];
      //var ambiguousSetArray = ["(",")","{","}","[","]","(",")","/","~",";",":",".","<",">"];
      var passwordArray = [];
      var digitsArray = [];
      var digitsPositionArray = [];


      // first, fill the password array with letters, uppercase and lowecase
      for (var i = 0; i < this.settings.length; i++) {
        // get an array for all indexes of the password array
        digitsPositionArray.push(i);

        var upperCase = Math.round(Math.random() * 1);
        if (upperCase === 0) {
          passwordArray[i] = lettersSetArray[Math.floor(Math.random()*lettersSetArray.length)].toUpperCase();
        }
        else {
          passwordArray[i] = lettersSetArray[Math.floor(Math.random()*lettersSetArray.length)];
        }
      }

      // Add digits to password
      for (i = 0; i < this.settings.digits; i++) {
        digit = Math.round(Math.random() * 9);
        numberIndex = digitsPositionArray[Math.floor(Math.random()*digitsPositionArray.length)];

        passwordArray[numberIndex] =  digit;

        /* remove position from digitsPositionArray so we make sure to the have the exact number of digits in our password
        since without this step, numbers may override other numbers */

        var j = digitsPositionArray.indexOf(numberIndex);
        if(i != -1) {
          digitsPositionArray.splice(j, 1);
        }
      }

      // add special charachters "symbols"
      for (i = 0; i < this.settings.symbols; i++) {
        var symbol = symbolsSetArray[Math.floor(Math.random()*symbolsSetArray.length)];
        var symbolIndex = digitsPositionArray[Math.floor(Math.random()*digitsPositionArray.length)];

        passwordArray[symbolIndex] =  symbol;

        /* remove position from digitsPositionArray so we make sure to the have the exact number of digits in our password
        since without this step, numbers may override other numbers */

        var j = digitsPositionArray.indexOf(symbolIndex);
        if(i != -1) {
          digitsPositionArray.splice(j, 1);
        }
      }
      this.password = passwordArray.join("");
    },
  },
});

这个密码生成器使用Math.random,获取包含大写和小写字母的密码数组,然后将随机数字添加到生成的密码中。这是另一个很实用的例子

值得关注的事情

Math.random()真的是随机的吗?

不完全是。 Math.random()返回一个伪随机数。 该算法称为伪随机数生成器(或PRNG)。 这意味着在某些情况下能够控制其随机性。

这一随机化是基于xorshift128 +算法,该算法可能在您的浏览器上运行。

所以,它是随机的。

如何处理重复值?

有许多方法可以在不重复的情况下获得独特的值。Fisher-Yates是一种通过改变数组序列来防止两次获得相同数字的好方法。 Math.random将从有限序列的变化数组中选择一个值,如下面的代码片段所示。

function shuffle (array) {
  var i = 0
    , j = 0
    , temp = null

  for (i = array.length - 1; i > 0; i -= 1) {
    j = Math.floor(Math.random() * (i + 1))
    temp = array[i]
    array[i] = array[j]
    array[j] = temp
  }
}

Math.random()与WebCrypto相同吗?

如您在本文中所见,Math.random()非常棒!但是,如果您要处理敏感的应用程序,并且需要一种更安全的随机方法,则建议您使用WebCrypto。 您可能要使用WebCrypto的原因包括临时验证码,随机密码生成,随机彩票号码等。

如果出于网络安全、密码学或统计的目的需要随机化,请使用window.crypto.getRandomValues 函数,相关内容请查看Mozilla关于WebCrypto API的文档。

你可能感兴趣的:(JavaScript专题,javascript,Math.random函数,外文翻译,艺术创作)