Jump to content
Search Community

jgray

Members
  • Posts

    3
  • Joined

  • Last visited

Posts posted by jgray

  1. Hello,

     

    I am experiencing this issue as well with trying to use vector-effect="non-scaling-stroke" in combination with the DrawSVG plugin on a circle element and causing crazy behavior. I've created a codepen that links to the DrawSVGPlugin referenced above highlighting the two outcomes with/without the non-scaling-stroke attribute. Is this the same issue or something else?

     

    See the Pen mjBbaO by ventinus (@ventinus) on CodePen

  2. I know I'm coming to this post way late but I ran into the same issue where I was losing a class name I had wrapped part of the text I was then splitting into lines. I'm not sure if this is something that has since been supported and I'm also a noob at GSAP as I've only been using it for the past week. But, for any future visitors perhaps wondering if there's a workaround, I've devised a solution that grabs the text within elements of a specified class to then wrap that same text with spans with that same class. The only caveat (that I know of) is if a block of text (single word/character or more with the special class) occurs more than once in the entire split line text block, it will be applied to the first match.

     

    consider the following markup:

    <p class="target">this is some <span class="special">special</span> text.</p>

     

    would merit the following js:

    const target = document.querySelector('.target')
    // target needs to be cloned because splitText mutates the passed element as well as any references
    const original = target.cloneNode(true)
    const splitTarget = new SplitText(target, {type: 'lines'})
    const preservedSplitTarget = preserveClass(splitTarget, original, '.special')
    
    // function to preserve a class on text split by lines. 
    // ideally imported from a helper file
    function preserveClass(splitText, original, className) {
      const texts = Array.from(original.querySelectorAll(className)).map(val => val.innerText.split(' '))
      // Check if any of the original element contains any children with the className
      if (texts.length === 0) return splitText
      
      // regex to match a text preceded by the beginning of the string or a space and has a space or non-word character or end of string after.
      const genWordRegex = word => new RegExp(`(?:^|\\s)${word}(?=\\s|\\W|$)`)
      // helper for quick splitting text on spaces and filtering out empty strings
      const splitInnerHTML = innerHTML => innerHTML.split(' ').filter(s => s.length > 0)
      const {lines} = splitText
      // template helper for wrapping text with spans using the className argument
      const spanTemplate = content => `<span class="${className.replace(/\./, '')}">${content}</span>`
      // tracks which occurrence of the class your tracking (the first level of the multidimensional array)
      let blockIndex = 0
      // the current block of text to wrap
      let textToPreserve = texts[blockIndex]
      // tracks which word in the block to look for
      let textIndex = 0
    
      // recursively checks the target text against the textArray (textToPreserve) and wraps matching text in target
      const recursiveSwap = (target, textArray) => {
        const textPiece = textArray[textIndex]
        const RE = genWordRegex(textPiece)
    
        // ensure that textPiece lives in the target before proceeding
        if (!RE.test(target)) return target
    
        const newTarget = target.replace(RE, first => {
          // since javascript doesnt support regex lookbehinds (yet), leading spaces are returned in the match so we want to preserve that
          const start = first.charAt(0) === ' ' ? ' ' : ''
          return `${start}${spanTemplate(textPiece)}`
        })
    
        textIndex = textIndex + 1
    
        // if we have reached the end of the current textBlock
        if (textIndex >= textArray.length) {
          blockIndex = blockIndex + 1
          // if we have reached the end of all textBlocks
          if (blockIndex >= texts.length) return newTarget
          textToPreserve = texts[blockIndex]
          textIndex = 0
        }
    
        return recursiveSwap(newTarget, textArray)
      }
    
      return {
        ...splitText,
        lines: lines.map((l, i, linesArray) => {
          let lineText = l.innerHTML
          // return the line if the next piece of text to preserve doesn't match
          if (!genWordRegex(textToPreserve[textIndex]).test(lineText)) return l
     	  
          // if we've already started replacing pieces in the current textBlock or there's only one item in the block
          if (textIndex > 0 || textToPreserve.length === 1) {
            l.innerHTML = recursiveSwap(lineText, textToPreserve)
          } else {
            let splitLine = splitInnerHTML(lineText)
            let currWordIndex = splitLine.indexOf(textToPreserve[textIndex])
            let nextWord = textToPreserve[1]
            // check if there are more words in the current line
            if (currWordIndex < splitLine.length - 1) {
              // check if the next words of both the textToPreserve and line match to ensure we start replacing the correct occurrence of a common word
              if (nextWord === splitLine[currWordIndex + 1]) {
                l.innerHTML = recursiveSwap(lineText, textToPreserve)
              }
            // else we've reached the end of the current line
            } else {
              // check if there is a next line and that the next textToPreserve word matches the first word in the next line
              if (i < linesArray.length - 1 && nextWord === splitInnerHTML(linesArray[i + 1].innerHTML)[0]) {
                l.innerHTML = recursiveSwap(lineText, textToPreserve)
              }
            }
          }
          return l
        })
      }
    }

     

    This is the first iteration of a workaround and certainly has room for improvement and I would love to hear any feedback/concerns regarding this approach. Hope this is of some help.

×
×
  • Create New...