{"id":1194,"date":"2023-04-06T13:38:42","date_gmt":"2023-04-06T10:38:42","guid":{"rendered":"https:\/\/notes.profidev.online\/?p=1194"},"modified":"2023-04-06T13:38:44","modified_gmt":"2023-04-06T10:38:44","slug":"typing-text-transition","status":"publish","type":"post","link":"https:\/\/notes.profidev.online\/ru\/elements\/1194\/","title":{"rendered":"Typing text transition"},"content":{"rendered":"\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe title=\"Typing text transition\" width=\"640\" height=\"360\" src=\"https:\/\/www.youtube.com\/embed\/pZ3loyTGLDk?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/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;p id=&quot;offscreen-text&quot; class=&quot;offscreen-text&quot;&gt;&lt;\/p&gt;\n  &lt;p id=&quot;text&quot; class=&quot;text&quot;&gt;&lt;\/p&gt;\n  \n  &lt;svg id=&quot;svg&quot;&gt;\n  &lt;\/svg&gt;\n  \n  &lt;input type=&quot;text&quot; class=&quot;input&quot;, id=&quot;input&quot; \/&gt;\n\n  &lt;script src=&quot;https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/gsap\/1.20.3\/plugins\/CSSPlugin.min.js&quot;&gt;&lt;\/script&gt;\n  &lt;script src=&quot;https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/gsap\/1.20.3\/easing\/EasePack.min.js&quot;&gt;&lt;\/script&gt;\n  &lt;script src=&quot;https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/gsap\/1.20.3\/TweenLite.min.js&quot;&gt;&lt;\/script&gt;<\/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;}\">html, body {\n  width: 100%;\n  height: 100%;\n  overflow: hidden;\n  font-family: 'Rubik Mono One', sans-serif;\n  background: #22292C;\n}\n\nsvg {\n  width: 100%;\n  height: 100%;\n  position: absolute;\n  top: 0px;\n  left: 0px;\n  z-index: 0;\n}\n\n.input {\n  position: absolute;\n  z-index: 1;\n  bottom: 0px;\n  font-size: 20px;\n  text-align: center;\n  left: 50%;\n  transform: translateX(-50%);\n  font-family: helvetica, sans-serif;\n  bottom: 20px;\n  background: none;\n  border: 1px solid #ddd;\n  color: #eee;\n}\n\n.text, .offscreen-text {\n  width: 100%;\n  top: 50%;\n  transform: translateY(-50%);\n  display: block;\n  position: absolute;\n  margin: 0;\n}\n\n.offscreen-text {\n  text-align: center;\n  top: -9999px;\n}\n\n.text span {\n  position: absolute;\n}\n\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;}\">const selectSVG = id =&gt; {\n  const el = document.getElementById(id);\n  return new SVGElement(el);\n};\n\nconst createSVG = type =&gt; {\n  const el = document.createElementNS('http:\/\/www.w3.org\/2000\/svg', type);\n  return new SVGElement(el);\n};\n\nclass SVGElement {\n  constructor(element) {\n    this.element = element;\n  }\n\n  set(attributeName, value) {\n    this.element.setAttribute(attributeName, value);\n  }\n\n  style(property, value) {\n    this.element.style[property] = value;\n  }\n}\n\nconst colors = [\n  { main: '#FBDB4A', shades: ['#FAE073', '#FCE790', '#FADD65', '#E4C650'] },\n  { main: '#F3934A', shades: ['#F7B989', '#F9CDAA', '#DD8644', '#F39C59'] },\n  { main: '#EB547D', shades: ['#EE7293', '#F191AB', '#D64D72', '#C04567'] },\n  { main: '#9F6AA7', shades: ['#B084B6', '#C19FC7', '#916198', '#82588A'] },\n  { main: '#5476B3', shades: ['#6382B9', '#829BC7', '#4D6CA3', '#3E5782'] },\n  { main: '#2BB19B', shades: ['#4DBFAD', '#73CDBF', '#27A18D', '#1F8171'] },\n  { main: '#70B984', shades: ['#7FBE90', '#98CBA6', '#68A87A', '#5E976E'] }\n];\nconst svg = selectSVG('svg');\nconst text = document.getElementById('text');\nconst offscreenText = document.getElementById('offscreen-text');\nconst input = document.getElementById('input');\nlet width = window.innerWidth;\nlet height = window.innerHeight;\nlet textSize = 0;\nlet textCenter = 0;\nconst letters = [];\nconst prompt = ['s', 't', 'a', 'r', 't', ' ', 't', 'y', 'p', 'i', 'n', 'g'];\nlet runPrompt = true;\n\nconst resizePage = () =&gt; {\n  width = window.innerWidth;\n  height = window.innerHeight;\n  svg.set('height', height);\n  svg.set('width', width);\n  svg.set('viewBox', `0 0 ${width} ${height}`);\n  resizeLetters();\n}\n\nconst resizeLetters = () =&gt; {\n  textSize = width \/ (letters.length+2);\n  if (textSize &gt; 100) textSize = 100;\n  text.style.fontSize = `${textSize}px`;\n  text.style.height = `${textSize}px`;\n  text.style.lineHeight = `${textSize}px`;\n  offscreenText.style.fontSize = `${textSize}px`;\n  const textRect = text.getBoundingClientRect();\n  textCenter = textRect.top + textRect.height\/2;\n  positionLetters();\n};\n\nconst positionLetters = () =&gt; {\n  letters.forEach(letter =&gt; {\n    const timing = letter.shift ? 0.1 : 0;\n    TweenLite.to(letter.onScreen, timing, {x:letter.offScreen.offsetLeft+'px', ease: Power3.easeInOut});\n    letter.shift = true;\n  });\n}\n\nconst animateLetterIn = letter =&gt; {\n  const yOffset = (0.5+Math.random()*0.5) * textSize;\n  TweenLite.fromTo(letter, 0.4, {scale:0}, {scale:1, ease: Back.easeOut});\n  TweenLite.fromTo(letter, 0.4, {opacity:0}, {opacity: 1, ease: Power3.easeOut});\n  TweenLite.to(letter, 0.2, {y:-yOffset, ease: Power3.easeInOut});\n  TweenLite.to(letter, 0.2, {y:0, ease: Power3.easeInOut, delay: 0.2});\n  const rotation = -50 + Math.random()*100;\n  TweenLite.to(letter, 0.2, {rotation: rotation, ease: Power3.easeInOut});\n  TweenLite.to(letter, 0.2, {rotation: 0, ease: Power3.easeInOut, delay: 0.2});\n}\n\nconst addDecor = (letter, color) =&gt; {\n  setTimeout(() =&gt; {\n    var rect = letter.getBoundingClientRect();\n    const x0 = letter.offsetLeft + letter.offsetWidth\/2;\n    const y0 = textCenter - textSize*0.5;\n    const shade = color.shades[Math.floor(Math.random()*4)];\n    for (var i = 0; i &lt; 8; i++) addTri(x0, y0, shade);\n    for (var i = 0; i &lt; 8; i++) addCirc(x0, y0);\n  }, 150);\n};\n\nconst addTri = (x0, y0, shade) =&gt; {\n  const tri = createSVG('polygon');\n  const a = Math.random();\n  const a2 = a + (-0.2 + Math.random()*0.4);\n  const r = textSize*0.52;\n  const r2 = r + textSize*Math.random()*0.2;\n  const x = x0 + r * Math.cos(2 * Math.PI * a);\n  const y = y0 + r * Math.sin(2 * Math.PI * a);\n  const x2 = x0 + r2 * Math.cos(2 * Math.PI * a2);\n  const y2 = y0 + r2 * Math.sin(2 * Math.PI * a2);\n  const triSize = textSize * 0.1;\n  const scale = 0.3 + Math.random()*0.7;\n  const offset = triSize*scale;\n  tri.set('points', `0,0 ${triSize*2},0 ${triSize},${triSize*2}`);\n  tri.style('fill', shade);\n  svg.element.appendChild(tri.element);\n  TweenLite.fromTo(tri.element, 0.6, {rotation: Math.random()*360, scale: scale, x: x-offset, y: y-offset, opacity: 1}, {x: x2-offset, y: y2-offset, opacity: 0, ease: Power1.easeInOut, onComplete: () =&gt; {\n    svg.element.removeChild(tri.element);\n  }});\n}\n\nconst addCirc = (x0, y0) =&gt; {\n  const circ = createSVG('circle');\n  const a = Math.random();\n  const r = textSize*0.52;\n  const r2 = r + textSize;\n  const x = x0 + r * Math.cos(2 * Math.PI * a);\n  const y = y0 + r * Math.sin(2 * Math.PI * a);\n  const x2 = x0 + r2 * Math.cos(2 * Math.PI * a);\n  const y2 = y0 + r2 * Math.sin(2 * Math.PI * a);\n  const circSize = textSize * 0.05 * Math.random();\n  circ.set('r', circSize);\n  circ.style('fill', '#eee');\n  svg.element.appendChild(circ.element);\n  TweenLite.fromTo(circ.element, 0.6, {x: x-circSize, y: y-circSize, opacity: 1}, {x: x2-circSize, y: y2-circSize, opacity: 0, ease: Power1.easeInOut, onComplete: () =&gt; {\n    svg.element.removeChild(circ.element);\n  }});\n}\n\nconst addLetter = (char, i) =&gt; {\n  const letter = document.createElement('span');\n  const oLetter = document.createElement('span');\n  letter.innerHTML = char;\n  oLetter.innerHTML = char;\n  text.appendChild(letter);\n  const color = colors[i%colors.length];\n  letter.style.color = color.main;\n  offscreenText.appendChild(oLetter);\n  letters[i] = {offScreen: oLetter, onScreen: letter, char: char};\n  animateLetterIn(letter);\n  addDecor(oLetter, color);\n}\n\nconst addLetters = value =&gt; {\n  value.forEach((char, i) =&gt; {\n    if (letters[i] &amp;&amp; letters[i].char !== char) {\n      letters[i].onScreen.innerHTML = char;\n      letters[i].offScreen.innerHTML = char;\n      letters[i].char = char;\n    }\n    if (letters[i] === undefined) {\n      addLetter(char, i);\n    }\n  });\n};\n\nconst animateLetterOut = (letter, i) =&gt; {\n  TweenLite.to(letter.onScreen, 0.1, {scale: 0, opacity: 0, ease: Power2.easeIn, onComplete: () =&gt; {\n    console.log('removing');\n    console.log(letter);\n    offscreenText.removeChild(letter.offScreen);\n    text.removeChild(letter.onScreen);\n    positionLetters();\n  }});\n  letters.splice(i, 1);\n}\n\nconst removeLetters = value =&gt; {\n  for (let i = letters.length-1; i &gt;= 0; i--) {\n    const letter = letters[i];\n    if (value[i] === undefined) {\n      animateLetterOut(letter, i)\n    }\n  }\n}\n\nconst onInputChange = () =&gt; {\n  const value = input.value === '' ? [] : input.value.toLowerCase().split('');\n  addLetters(value);\n  removeLetters(value);\n  resizeLetters();\n};\n\nconst keyup = (e) =&gt; {\n  if (runPrompt) {\n    input.value = '';\n    runPrompt = false;\n  };\n  onInputChange();\n}\n\nconst addPrompt = (i) =&gt; {\n  setTimeout(() =&gt; {\n    if (runPrompt &amp;&amp; prompt[i]) {\n      input.value = input.value + prompt[i];\n      onInputChange();\n      addPrompt(i+1);\n    }\n  }, 300);\n}\n  \nresizePage();\nwindow.addEventListener('resize', resizePage);\ninput.addEventListener('keyup', keyup);\ninput.focus();\naddPrompt(0);<\/pre><\/div>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":1195,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[19],"tags":[27,40],"class_list":["post-1194","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-elements","tag-gsap","tag-text"],"_links":{"self":[{"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/posts\/1194","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=1194"}],"version-history":[{"count":1,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/posts\/1194\/revisions"}],"predecessor-version":[{"id":1196,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/posts\/1194\/revisions\/1196"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/media\/1195"}],"wp:attachment":[{"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/media?parent=1194"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/categories?post=1194"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/notes.profidev.online\/ru\/wp-json\/wp\/v2\/tags?post=1194"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}