{"id":3048,"date":"2021-07-03T12:39:58","date_gmt":"2021-07-03T12:39:58","guid":{"rendered":"https:\/\/rengga.dev\/blog\/?p=3048"},"modified":"2023-02-28T03:51:40","modified_gmt":"2023-02-28T03:51:40","slug":"js-tutorial-math-random-animation","status":"publish","type":"post","link":"https:\/\/rengga.dev\/blog\/js-tutorial-math-random-animation\/","title":{"rendered":"JS Tutorial &#8211; Math.random() Animation"},"content":{"rendered":"<p><span style=\"color: #ef3207;\"><a style=\"color: #ef3207;\" href=\"https:\/\/rengga.dev\/\" target=\"_blank\" rel=\"noopener\"><strong>Rengga Dev<\/strong><\/a> <\/span>&#8211; <code>Math.random()<\/code>\u00a0is an API in JavaScript. It is a function that gives you a random number. The number returned will be between 0 (inclusive, as in, it\u2019s possible for an actual 0 to be returned) and 1 (exclusive, as in, it\u2019s not possible for an actual 1 to be returned).<\/p>\n<p>To spawn an object and animate it, we use\u00a0<code>Math.random<\/code>. The neon lines form spontaneous hexagons but randomization is also in its generative sparks.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\">var w = c.width = window.innerWidth,\r\n    h = c.height = window.innerHeight,\r\n    ctx = c.getContext( '2d' ),\r\n    \r\n    opts = {\r\n      \r\n      len: 20,\r\n      count: 50,\r\n      baseTime: 10,\r\n      addedTime: 10,\r\n      dieChance: .05,\r\n      spawnChance: 1,\r\n      sparkChance: .1,\r\n      sparkDist: 10,\r\n      sparkSize: 2,\r\n      \r\n      color: 'hsl(hue,100%,light%)',\r\n      baseLight: 50,\r\n      addedLight: 10, \/\/ [50-10,50+10]\r\n      shadowToTimePropMult: 6,\r\n      baseLightInputMultiplier: .01,\r\n      addedLightInputMultiplier: .02,\r\n      \r\n      cx: w \/ 2,\r\n      cy: h \/ 2,\r\n      repaintAlpha: .04,\r\n      hueChange: .1\r\n    },\r\n    \r\n    tick = 0,\r\n    lines = [],\r\n    dieX = w \/ 2 \/ opts.len,\r\n    dieY = h \/ 2 \/ opts.len,\r\n    \r\n    baseRad = Math.PI * 2 \/ 6;\r\n    \r\nctx.fillStyle = 'black';\r\nctx.fillRect( 0, 0, w, h );\r\n\r\nfunction loop() {\r\n  \r\n  window.requestAnimationFrame( loop );\r\n  \r\n  ++tick;\r\n  \r\n  ctx.globalCompositeOperation = 'source-over';\r\n  ctx.shadowBlur = 0;\r\n  ctx.fillStyle = 'rgba(0,0,0,alp)'.replace( 'alp', opts.repaintAlpha );\r\n  ctx.fillRect( 0, 0, w, h );\r\n  ctx.globalCompositeOperation = 'lighter';\r\n  \r\n  if( lines.length &lt; opts.count &amp;&amp; Math.random() &lt; opts.spawnChance )\r\n    lines.push( new Line );\r\n  \r\n  lines.map( function( line ){ line.step(); } );\r\n}\r\nfunction Line(){\r\n  \r\n  this.reset();\r\n}\r\nLine.prototype.reset = function(){\r\n  \r\n  this.x = 0;\r\n  this.y = 0;\r\n  this.addedX = 0;\r\n  this.addedY = 0;\r\n  \r\n  this.rad = 0;\r\n  \r\n  this.lightInputMultiplier = opts.baseLightInputMultiplier + opts.addedLightInputMultiplier * Math.random();\r\n  \r\n  this.color = opts.color.replace( 'hue', tick * opts.hueChange );\r\n  this.cumulativeTime = 0;\r\n  \r\n  this.beginPhase();\r\n}\r\nLine.prototype.beginPhase = function(){\r\n  \r\n  this.x += this.addedX;\r\n  this.y += this.addedY;\r\n  \r\n  this.time = 0;\r\n  this.targetTime = ( opts.baseTime + opts.addedTime * Math.random() ) |0;\r\n  \r\n  this.rad += baseRad * ( Math.random() &lt; .5 ? 1 : -1 );\r\n  this.addedX = Math.cos( this.rad );\r\n  this.addedY = Math.sin( this.rad );\r\n  \r\n  if( Math.random() &lt; opts.dieChance || this.x &gt; dieX || this.x &lt; -dieX || this.y &gt; dieY || this.y &lt; -dieY )\r\n    this.reset();\r\n}\r\nLine.prototype.step = function(){\r\n  \r\n  ++this.time;\r\n  ++this.cumulativeTime;\r\n  \r\n  if( this.time &gt;= this.targetTime )\r\n    this.beginPhase();\r\n  \r\n  var prop = this.time \/ this.targetTime,\r\n      wave = Math.sin( prop * Math.PI \/ 2  ),\r\n      x = this.addedX * wave,\r\n      y = this.addedY * wave;\r\n  \r\n  ctx.shadowBlur = prop * opts.shadowToTimePropMult;\r\n  ctx.fillStyle = ctx.shadowColor = this.color.replace( 'light', opts.baseLight + opts.addedLight * Math.sin( this.cumulativeTime * this.lightInputMultiplier ) );\r\n  ctx.fillRect( opts.cx + ( this.x + x ) * opts.len, opts.cy + ( this.y + y ) * opts.len, 2, 2 );\r\n  \r\n  if( Math.random() &lt; opts.sparkChance )\r\n    ctx.fillRect( opts.cx + ( this.x + x ) * opts.len + Math.random() * opts.sparkDist * ( Math.random() &lt; .5 ? 1 : -1 ) - opts.sparkSize \/ 2, opts.cy + ( this.y + y ) * opts.len + Math.random() * opts.sparkDist * ( Math.random() &lt; .5 ? 1 : -1 ) - opts.sparkSize \/ 2, opts.sparkSize, opts.sparkSize )\r\n}\r\nloop();\r\n\r\nwindow.addEventListener( 'resize', function(){\r\n  \r\n  w = c.width = window.innerWidth;\r\n  h = c.height = window.innerHeight;\r\n  ctx.fillStyle = 'black';\r\n  ctx.fillRect( 0, 0, w, h );\r\n  \r\n  opts.cx = w \/ 2;\r\n  opts.cy = h \/ 2;\r\n  \r\n  dieX = w \/ 2 \/ opts.len;\r\n  dieY = h \/ 2 \/ opts.len;\r\n});<\/pre>\n<p><iframe style=\"width: 100%;\" title=\"Math.random() Neon Xexagon-Forming Particles\" src=\"https:\/\/codepen.io\/renggagumilar\/embed\/ZExqaWg?default-tab=result&amp;theme-id=dark\" height=\"500\" frameborder=\"no\" scrolling=\"no\" allowfullscreen=\"allowfullscreen\"><br \/>\nSee the Pen <a href=\"https:\/\/codepen.io\/renggagumilar\/pen\/ZExqaWg\"><br \/>\nMath.random() Neon Xexagon-Forming Particles<\/a> by Rengga Gumilar (<a href=\"https:\/\/codepen.io\/renggagumilar\">@renggagumilar<\/a>)<br \/>\non <a href=\"https:\/\/codepen.io\">CodePen<\/a>.<br \/>\n<\/iframe><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Rengga Dev &#8211; Math.random()\u00a0is an API in JavaScript. It is a function <a class=\"read-more\" href=\"https:\/\/rengga.dev\/blog\/js-tutorial-math-random-animation\/\" title=\"JS Tutorial &#8211; Math.random() Animation\" itemprop=\"url\"><\/a><\/p>\n","protected":false},"author":1,"featured_media":3808,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[20],"tags":[275,264,263,274,103,227],"newstopic":[],"class_list":{"0":"post-3048","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","7":"category-javascript","8":"tag-animation","9":"tag-javascript-tutorial","10":"tag-js-tutorial","11":"tag-math-random","12":"tag-web-design","13":"tag-web-designer"},"_links":{"self":[{"href":"https:\/\/rengga.dev\/blog\/wp-json\/wp\/v2\/posts\/3048","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rengga.dev\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rengga.dev\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rengga.dev\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/rengga.dev\/blog\/wp-json\/wp\/v2\/comments?post=3048"}],"version-history":[{"count":2,"href":"https:\/\/rengga.dev\/blog\/wp-json\/wp\/v2\/posts\/3048\/revisions"}],"predecessor-version":[{"id":3051,"href":"https:\/\/rengga.dev\/blog\/wp-json\/wp\/v2\/posts\/3048\/revisions\/3051"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/rengga.dev\/blog\/wp-json\/wp\/v2\/media\/3808"}],"wp:attachment":[{"href":"https:\/\/rengga.dev\/blog\/wp-json\/wp\/v2\/media?parent=3048"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rengga.dev\/blog\/wp-json\/wp\/v2\/categories?post=3048"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rengga.dev\/blog\/wp-json\/wp\/v2\/tags?post=3048"},{"taxonomy":"newstopic","embeddable":true,"href":"https:\/\/rengga.dev\/blog\/wp-json\/wp\/v2\/newstopic?post=3048"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}