{"id":505,"date":"2023-03-08T17:35:45","date_gmt":"2023-03-08T14:35:45","guid":{"rendered":"https:\/\/notes.profidev.online\/?p=505"},"modified":"2023-03-28T18:14:02","modified_gmt":"2023-03-28T15:14:02","slug":"dots-effect","status":"publish","type":"post","link":"https:\/\/notes.profidev.online\/ru\/effect\/505\/","title":{"rendered":"Dots effect"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<figure class=\"wp-block-video\"><video height=\"859\" style=\"aspect-ratio: 1629 \/ 859;\" width=\"1629\" controls src=\"https:\/\/notes.profidev.online\/wp-content\/uploads\/2023\/03\/vokoscreenng-2023-03-08_15-27-16.webm\"><\/video><\/figure>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;htmlmixed&quot;,&quot;mime&quot;:&quot;text\/html&quot;,&quot;theme&quot;:&quot;cobalt&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:false,&quot;fileName&quot;:&quot;&quot;,&quot;TrpContentRestriction&quot;:{&quot;restriction_type&quot;:&quot;exclude&quot;,&quot;selected_languages&quot;:[],&quot;panel_open&quot;:true},&quot;language&quot;:&quot;HTML&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;html&quot;}\">&lt;canvas id=&quot;canvas-number&quot;&gt;&lt;\/canvas&gt;\n&lt;canvas id=&quot;canvas-dots&quot;&gt;&lt;\/canvas&gt;\n\n&lt;script src=&quot;\/\/cdnjs.cloudflare.com\/ajax\/libs\/gsap\/1.16.1\/TweenMax.min.js&quot;&gt;&lt;\/script&gt;\n\/\/\u0421\u043a\u0440\u0438\u043f\u0442 js \u043d\u0430\u0434\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0437\u0434\u0435\u0441\u044c\n\/\/\u0410\u0432\u0442\u043e\u0440: Nikolay Talanov. @suez<\/pre><\/div>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;css&quot;,&quot;mime&quot;:&quot;text\/css&quot;,&quot;theme&quot;:&quot;cobalt&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:false,&quot;fileName&quot;:&quot;&quot;,&quot;TrpContentRestriction&quot;:{&quot;restriction_type&quot;:&quot;exclude&quot;,&quot;selected_languages&quot;:[],&quot;panel_open&quot;:true},&quot;language&quot;:&quot;CSS&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;css&quot;}\">@font-face {\n  font-family: 'Lato';\n  font-style: normal;\n  font-weight: 900;\n  src: url(https:\/\/fonts.gstatic.com\/s\/lato\/v23\/S6u9w4BMUTPHh50XSwiPHA.ttf) format('truetype');\n}\nbody {\n  background-color: #24282f;\n  margin: 0;\n  padding: 0;\n}\ncanvas {\n  position: absolute;\n  top: 0;\n  left: 0;\n}\n#canvas-number {\n  width: 680px;\n  height: 420px;\n}<\/pre><\/div>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;javascript&quot;,&quot;mime&quot;:&quot;text\/javascript&quot;,&quot;theme&quot;:&quot;cobalt&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:false,&quot;fileName&quot;:&quot;&quot;,&quot;TrpContentRestriction&quot;:{&quot;restriction_type&quot;:&quot;exclude&quot;,&quot;selected_languages&quot;:[],&quot;panel_open&quot;:true},&quot;language&quot;:&quot;JavaScript&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;js&quot;}\">\/*\nDesc: Define inital variables\n*\/\nvar numberStage,\n\t\tnumberStageCtx,\n\t  numberStageWidth = 680,\n\t\tnumberStageHeight = 420,\n\t\tnumberOffsetX,\n\t\tnumberOffsetY,\n\t\t\n\t\tstage,\n\t\tstageCtx,\n\t\tstageWidth   = window.innerWidth,\n\t\tstageHeight  = window.innerHeight,\n\t\tstageCenterX = stageWidth\/2,\n\t\tstageCenterY = stageHeight\/2,\n\t\t\n\t\tcountdownFrom = 10,\n\t\tcountdownTimer = 2800,\n\t\tcountdownRunning = true,\n\t\t\n\t\tnumber,\n\t\tdots = [],\n\t\tnumberPixelCoordinates,\n\t\tcircleRadius = 2,\n\t\tcolors = ['61, 207, 236', '255, 244, 174', '255, 211, 218', '151, 211, 226'];\n\n\n\/*\nDesc: Init canvases &amp; Number text\n*\/\nfunction init() {\n\n\t\t\t\/\/ Init stage which will have numbers\n\t\t\tnumberStage = document.getElementById(&quot;canvas-number&quot;);\n\t\t\tnumberStageCtx = numberStage.getContext('2d');\n\t\t\t\/\/ Set the canvas to width and height of the window\n\t\t\tnumberStage.width = numberStageWidth;\n\t\t\tnumberStage.height = numberStageHeight;\n\t\t\t\n\t\t\t\/\/ Init Stage which will have dots\n\t\t\tstage = document.getElementById(&quot;canvas-dots&quot;);\n\t\t\tstageCtx = stage.getContext('2d');\n      stage.width = stageWidth;\n      stage.height = stageHeight;\n\t\n\t\t\t\/\/ Create offset so text appears in middle of screen\n\t   \tnumberOffsetX = (stageWidth - numberStageWidth) \/ 2;\n\t\t\tnumberOffsetY = (stageHeight - numberStageHeight) \/ 2;\n}\n\ninit();\n\n\n\/*\nDesc: Dot object\n*\/\nfunction Dot(x, y, color, alpha) {\n\t\n\tvar _this = this;\n\t\n\t_this.x = x;\n\t_this.y = y;\n\t_this.color = color;\n\t_this.alpha = alpha;\n\t\n\tthis.draw = function() {\n\t\tstageCtx.beginPath();\n\t\tstageCtx.arc(_this.x, _this.y, circleRadius, 0, 2*Math.PI, false);\n\t\tstageCtx.fillStyle = 'rgba(' + _this.color + ', ' + _this.alpha + ')';\n\t\tstageCtx.fill();\n\t}\n\t\n}\n\n\/*\nDesc: Create a certain amount of dots\n*\/\nfor (var i = 0; i &lt; 2240; i++) {\n\t\n\t\/\/ Create a dot\n\tvar dot = new Dot(randomNumber(0, stageWidth), randomNumber(0, stageHeight), colors[randomNumber(1, colors.length)], .3);\n\t\n\t\/\/ Push to into an array of dots\n\tdots.push(dot);\n\t\n\t\/\/ Animate dots\n\ttweenDots(dot, '', 'space');\t\n}\n\n\n\/*\nDesc: Countdown\n*\/\nfunction countdown() {\n\n\t\/\/ Send number to be drawn\n\tdrawNumber(countdownFrom.toString());\n\n\t\/\/ When we hit zero stop countdown\n\tif (countdownFrom === 0) {\n\t\tcountdownRunning = false;\n\t\t\/\/ Now that countdowns finised show the text Go\n\t\tdrawNumber('a');\n\t}\n\t\n\t\/\/ Decrement number down\n\tcountdownFrom--;\n}\ncountdown();\n\n\n\/*\nDesc: Redraw loops\n*\/\nfunction loop() {\n\t\n\tstageCtx.clearRect(0,0,stageWidth, stageHeight);\n  \t\n\tfor(var i = 0; i &lt; dots.length; i++) {\n   \tdots[i].draw(stageCtx);\n  }\n \t\n\trequestAnimationFrame(loop);\n}\n\nloop();\n\n\n\/*\nDesc: Draw number\n*\/\nfunction drawNumber(num) {\n\t\n\t\t\/\/ Create a number on a seperate canvas\n\t\t\/\/ Use a seperate canvas thats smaller so we have less data to loop over when using getImagedata()\n\t\t\n\t\t \/\/\tClear stage of previous numbers\n\t\t numberStageCtx.clearRect(0,0,numberStageWidth, numberStageHeight);\n\t\n\t\t numberStageCtx.fillStyle = &quot;#24282f&quot;;\n\t   numberStageCtx.textAlign = 'center';\n  \t numberStageCtx.font = &quot;bold 418px Lato&quot;;\n  \t numberStageCtx.fillText(num, 340, 400);\n\t\n\t\t var ctx = document.getElementById('canvas-number').getContext('2d');\n\t\t\t\n\t\t\t\/\/ getImageData(x, y, width, height)\n\t\t\t\/\/ note: is an exspenisve function, so make sure canvas is small as possible for what you grab\n\t\t\t\/\/ Returns 1 Dimensional array of pixel color value chanels\n\t\t\t\/\/ Red, blue, green, alpha chanel of single pixel\n\t    \/\/ First chanel is red\n\t\t\tvar imageData = ctx.getImageData(0,0,numberStageWidth,numberStageHeight).data;\n\n\t\t\t\/\/ Clear number coordinated\n\t\t\tnumberPixelCoordinates = [];\n\n\t\t\t\/\/ i is equal to total image data(eg: 480,000)\n\t    \/\/ run while i is greater or equal to 0\n\t \t  \/\/ every time we run it minus 4 from i. Do this because each pixel has 4 chanels &amp; we are only interested in individual pixels \n\t\t\tfor (var i = imageData.length; i &gt;= 0; i -= 4) {\n\n\t\t\t\t\t\t\/\/ If not an empty pixel\n\t\t\t\t\t\tif (imageData[i] !== 0) {\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\/\/ i represents the position in the array a red pixel was found\n\n\t\t\t\t\t\t\t\t\/\/ (i \/ 4 ) and percentage by width of canvas\n\t\t\t\t\t\t\t  \/\/ Need to divide i by 4 because it has 4 values and you need its orginal position\n\t\t\t\t\t\t\t  \/\/ Then you need to percentage it by the width(600) because each row contains 600 pixels and you need its relative position in that row\n\t\t\t\t\t\t\t\tvar x = (i \/ 4) % numberStageWidth;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\/\/ (i divide by width) then divide by 4\n\t\t\t\t\t\t\t\t\/\/ Divide by width(600) first so you get the rows of pixels that make up the canvas. Then divide by 4 to get its postion within the row\n\t\t\t\t\t\t\t \tvar y = Math.floor(Math.floor(i\/numberStageWidth)\/4);\n\n\t\t\t\t\t\t\t\t\/\/ If position exists and number is divisble by circle plus a pixel gap then add cordinates to array. So circles do not overlap\n\t\t\t\t\t\t\t \tif((x &amp;&amp; x%(circleRadius * 2 + 3) == 0) &amp;&amp; (y &amp;&amp; y%(circleRadius * 2 + 3) == 0)) {\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\/\/ Push object to numberPixels array with x and y coordinates\n\t\t\t\t\t\t\t\t\t\tnumberPixelCoordinates.push({x: x, y: y});\n\t\t\t\t\t\t\t\t\t\n            \t\t}\n\n\t\t\t\t\t\t}\n\t\t\t}\n\t\n\t\t\tformNumber();\n\n}\n\n\n\/*\nDesc: Form number\n*\/\nfunction formNumber() {\n\t\n\tfor (var i = 0; i &lt; numberPixelCoordinates.length; i++) {\n\t\t\n\t\t\/\/ Loop out as many coordionates as we need &amp; pass dots in to animate\n\t\t  tweenDots(dots[i], numberPixelCoordinates[i], '');\n\t}\n\t\n\t\/\/ Break number apart\n\tif (countdownRunning &amp;&amp; countdownFrom &gt; 0) {\n\t\tsetTimeout(function() {\n\t\t\t breakNumber();\n\t\t}, countdownTimer);\n\t}\n}\n\nfunction breakNumber() {\n\t\n\t\tfor (var i = 0; i &lt; numberPixelCoordinates.length; i++) {\n\t\t\ttweenDots(dots[i], '', 'space');\t\n\t\t}\n\t\n\t\tif (countdownRunning) {\n\t\t\t\/\/ Build next number\n\t\t\tsetTimeout(function() {\n\t\t\t\tcountdown();\n\t\t\t}, countdownTimer);\n\t\t}\n\n}\n\n\n\/*\nDesc: Animate dots\n*\/\nfunction tweenDots(dot, pos, type) {\n\t\t\n\t\/\/ Move dots around canvas randomly\n\tif (type === 'space') {\n\t\t\t\t\n\t\t\/\/ Tween dot to coordinate to form number\n\t\tTweenMax.to(dot, (3 + Math.round(Math.random() * 100) \/ 100), {\n\t\t\tx: randomNumber(0, stageWidth),  \n\t\t\ty: randomNumber(0, stageHeight),\n\t\t\talpha: 0.3,\n\t\t\tease: Cubic.easeInOut,\n\t\t\tonComplete: function() {\n\t\t\t\ttweenDots(dot, '', 'space');\n\t\t\t}\n\t\t});\n\t\t\n\t} else {\n\t\n\t\t\/\/ Tween dot to coordinate to form number\n\t\tTweenMax.to(dot, (1.5 + Math.round(Math.random() * 100) \/ 100), {\n\t\t\tx: (pos.x + numberOffsetX),\n\t\t\ty: (pos.y + numberOffsetY),\n\t\t\tdelay: 0,\n\t\t\talpha: 1,\n\t\t\tease: Cubic.easeInOut,\n\t\t\tonComplete: function() {\n\t\t\t}\n\t\t});\n\t\t\n\t}\n}\n\n\n\/*\nDesc: Get a random number\n*\/\nfunction randomNumber(min, max) {\n\treturn Math.floor(Math.random() * (max - min) + min);\n}<\/pre><\/div>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":507,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12],"tags":[38,39],"class_list":["post-505","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-effect","tag-canvas","tag-tweenmax"],"_links":{"self":[{"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/posts\/505","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/comments?post=505"}],"version-history":[{"count":0,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/posts\/505\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/media\/507"}],"wp:attachment":[{"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/media?parent=505"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/categories?post=505"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/tags?post=505"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}