{"version":3,"file":"869.a92c8a0055ee5f158c28.js","mappings":"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","sources":["webpack://pratt-parent/./static/js/components/tag.js"],"sourcesContent":["function shuffle(array) {\n for (let i = array.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n [array[i], array[j]] = [array[j], array[i]];\n }\n return array;\n}\n\nclass Tag {\n constructor(root, options) {\n this.root = root;\n this.wrapper = this.root.querySelector('.js-tags-wrapper');\n this.tagListItems = shuffle(Array.from(this.root.querySelectorAll('.js-tags-tag')));\n\n this.hasRendered = false;\n this.motionDisabled = false;\n this.options = {\n shape: options?.shape ?? 'ellipse',\n reverse: options?.reverse ?? false,\n };\n this.tagData = [];\n\n this.init();\n }\n\n init() {\n // Don't init if there are no tags\n if (!this.tagListItems.length) {\n return;\n }\n\n this.initElements();\n this.initEvents();\n this.initTagData();\n\n this.animate();\n }\n\n get wrapperRect() {\n const tagRects = this.tagListItems.map(tag => tag.getBoundingClientRect());\n const maxTagHeight = Math.max(...tagRects.map(rect => rect.height));\n const maxTagWidth = Math.max(...tagRects.map(rect => rect.width));\n\n const wrapperRect = this.wrapper.getBoundingClientRect();\n const wrapperWidth = wrapperRect.width - maxTagWidth;\n const wrapperHeight = wrapperRect.height - maxTagHeight;\n\n return {\n top: maxTagHeight / 2,\n left: maxTagWidth / 2,\n width: wrapperWidth,\n height: wrapperHeight,\n };\n }\n\n /**\n * Gets the duration of one orbit rotation, given that a orbit\n * perimeter of 750px should last 100,000ms.\n *\n * Equation: (100,000ms / 750px) = (y / perimeter)\n */\n get duration() {\n const rect = this.wrapperRect;\n const minorAxis = Math.min(rect.width, rect.height) / 2;\n const majorAxis = Math.max(rect.width, rect.height) / 2;\n const perimeter = 2 * Math.PI * Math.sqrt((minorAxis * 2 + majorAxis * 2) / 2);\n return perimeter * (100_000 / 750);\n }\n\n initElements() {\n const wrapperRect = this.wrapperRect;\n this.wrapper.style.setProperty('--top', `${wrapperRect.top}px`);\n this.wrapper.style.setProperty('--left', `${wrapperRect.left}px`);\n\n if (this.options.shape === 'ellipse') {\n this.circle = document.createElement('div');\n this.circle.classList.add('js-tags-circle');\n this.wrapper.appendChild(this.circle);\n } else if (this.options.shape === 'graph') {\n this.graphSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n this.wrapper.appendChild(this.graphSvg);\n this.graphSvgPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');\n this.graphSvg.appendChild(this.graphSvgPath);\n }\n }\n\n initEvents() {\n // Disable motion on user preference\n const mediaQuery = '(prefers-reduced-motion: reduce)';\n const mediaQueryList = window.matchMedia(mediaQuery);\n // Temporarily removing animation. Need for further conversation about tags. - AWH, 7/31/2023\n // this.motionDisabled = mediaQueryList.matches;\n this.motionDisabled = true;\n mediaQueryList.addEventListener('change', evt => {\n this.motionDisabled = evt.matches;\n });\n\n this.tagListItems.forEach(tagListItem => {\n // Disable animation on hover\n tagListItem.addEventListener('pointerover', () => {\n tagListItem.setAttribute('data-hover', 'true');\n });\n tagListItem.addEventListener('pointerleave', () => {\n tagListItem.removeAttribute('data-hover');\n });\n\n // Disable animation on focus\n tagListItem.addEventListener('focusin', () => {\n tagListItem.setAttribute('data-focus', 'true');\n });\n tagListItem.addEventListener('focusout', () => {\n tagListItem.removeAttribute('data-focus');\n });\n });\n\n const observer = new ResizeObserver(() => {\n this.initTagData();\n this.update();\n });\n observer.observe(this.wrapper);\n }\n\n initTagData() {\n const wrapperRect = this.wrapperRect;\n\n if (this.options.shape === 'graph') {\n this.graphSvg.setAttribute(\n 'viewBox',\n `0 0 ${Math.max(0, wrapperRect.width)} ${Math.max(0, wrapperRect.height)}`,\n );\n }\n\n // Randomize the angle the tags begin at\n const angleOffset = Math.PI * 2 * Math.random();\n\n this.tagData = this.tagListItems.map((tagListItem, index) => {\n const tagRect = tagListItem.getBoundingClientRect();\n\n const x = wrapperRect.width / 2 - tagRect.width / 2 + wrapperRect.left;\n const y = wrapperRect.height / 2 - tagRect.height / 2 + wrapperRect.top;\n\n const width = tagRect.width;\n const height = tagRect.height;\n\n let anglePosition;\n if (this.options.shape === 'graph' && this.tagListItems.length === 3) {\n // distribute tags along ellipse to form isosceles triangle\n // • • - • -\n const numPositions = 5;\n const position = [0, 1, 3][index];\n anglePosition = position / numPositions;\n } else {\n // otherwise, evenly distribute\n anglePosition = (index + 1) / this.tagListItems.length;\n }\n\n let startAngle = Math.PI * 2 * anglePosition + angleOffset;\n let curAngle = startAngle;\n if (this.tagData[index]) {\n startAngle = this.tagData[index]?.startAngle;\n curAngle = this.tagData[index]?.curAngle;\n }\n\n return { x, y, width, height, startAngle, curAngle };\n });\n }\n\n animate() {\n if (!this.hasRendered) {\n // Render the tags at least once\n this.update();\n this.wrapper.removeAttribute('aria-hidden');\n this.hasRendered = true;\n } else if (!this.motionDisabled) {\n // Continue moving so long as motion isn't disabled\n this.update();\n }\n\n // Loop\n requestAnimationFrame(() => this.animate());\n }\n\n update() {\n const wrapperRect = this.wrapperRect;\n\n // Keep track of all tag positions (centered around tag)\n const positions = [];\n\n // convert from ms (1000/s) to frames (60/s)\n const frameDuration = (this.duration / 1000) * 60;\n const direction = this.options.reverse ? 1 : -1;\n const angleChange = (direction * (Math.PI * 2)) / frameDuration;\n\n this.tagListItems.forEach((tagListItem, index) => {\n if (!tagListItem.dataset.hover && !tagListItem.dataset.focus) {\n this.tagData[index].curAngle += angleChange;\n }\n\n // https://www.mathopenref.com/coordparamellipse.html\n // Calculate the tag x position\n const a = wrapperRect.width / 2;\n const x = a * Math.cos(this.tagData[index].curAngle) * -1;\n // Calculate the tag y position\n const b = wrapperRect.height / 2;\n const y = b * Math.sin(this.tagData[index].curAngle);\n\n // Update the tag's translation\n tagListItem.style.transform = `translateX(${this.tagData[index].x + x}px) translateY(${\n this.tagData[index].y + y\n }px)`;\n\n // And log the position (centered in the tag)\n positions.push({\n x: this.tagData[index].x + x + this.tagData[index].width / 2 - wrapperRect.left,\n y: this.tagData[index].y + y + this.tagData[index].height / 2 - wrapperRect.top,\n });\n });\n\n if (this.options.shape === 'graph') {\n // Generate the graph path\n const [first, ...rest] = positions;\n // Move point to first position\n let pathD = `M ${first.x} ${first.y} `;\n rest.forEach(position => {\n // Draw lines to subsequent positions\n pathD += `L ${position.x} ${position.y} `;\n });\n // Then close the path\n pathD += 'Z';\n this.graphSvgPath.setAttribute('d', pathD);\n }\n }\n}\n\nexport default Tag;\n"],"names":["constructor","root","options","this","wrapper","querySelector","tagListItems","array","i","length","j","Math","floor","random","shuffle","Array","from","querySelectorAll","hasRendered","motionDisabled","shape","reverse","tagData","init","initElements","initEvents","initTagData","animate","wrapperRect","tagRects","map","tag","getBoundingClientRect","maxTagHeight","max","rect","height","maxTagWidth","width","top","left","duration","minorAxis","min","majorAxis","PI","sqrt","style","setProperty","circle","document","createElement","classList","add","appendChild","graphSvg","createElementNS","graphSvgPath","mediaQueryList","window","matchMedia","addEventListener","evt","matches","forEach","tagListItem","setAttribute","removeAttribute","ResizeObserver","update","observe","angleOffset","index","tagRect","x","y","anglePosition","startAngle","curAngle","requestAnimationFrame","positions","frameDuration","angleChange","dataset","hover","focus","cos","sin","transform","push","first","rest","pathD","position"],"sourceRoot":""}