Search code examples
javascriptcsssvginfinite-scroll

How to replace emoji with a custom SVG image or PNG in a curved SVG path and apply rotation with custom CSS class?


I’m working with an SVG element where I have a marquee effect with curved text using the <textpath> element. Currently, I am using the 🌟 emoji as a part of the marquee text, but I would like to replace this emoji with a custom SVG image and rotate the image around its axis.

The problem I’m encountering is that when I replace the emoji with a custom image (either through an <img> tag or inline SVG), the image doesn’t appear, and the text simply shows. Additionally, I want to apply a custom class to this image for styling (e.g., to rotate it). However, whenever I try to add the class to the emoji, it disappears.

What I’ve Tried:

Replacing the emoji with an inline <img> tag that references the custom SVG image or an SVG element inline.

Applying custom CSS classes like .rotate-image to rotate the image.

Expected Outcome:

The custom SVG image should appear in the marquee path instead of the 🌟 emoji.

The image should be styled using a custom class (e.g., .rotate-image) for rotation.

The image should rotate smoothly using the defined CSS animation.

Issue:

The custom image doesn’t appear when I replace the emoji. Only the text shows up, not the image.

If I try to insert the custom image or use inline HTML elements, the image disappears, leaving only the text behind.

Can anyone suggest a solution or provide guidance on how I can successfully replace the emoji with a custom SVG image in the <textpath> and apply a custom CSS class for rotation and styling?

Here’s the code I’m currently working with:

function startMarquee(id, pathId, content, speed) {
  const textPath   = document.getElementById(id);
  const path       = document.getElementById(pathId);
  const pathLength = path.getTotalLength();

  textPath.innerHTML = content;

  let offset = 0;

  function animateText() {
    offset = (offset + speed) % pathLength;
    textPath.setAttribute('startOffset', `${offset}px`);
    requestAnimationFrame(animateText);
  }

  requestAnimationFrame(animateText);
}

document.addEventListener('DOMContentLoaded', () => {
  const textContent = "Web Design&nbsp;&nbsp;&nbsp;🌟&nbsp;&nbsp;&nbsp;Web Development&nbsp;&nbsp;&nbsp;🌟&nbsp;&nbsp;&nbsp;UI/UX Design&nbsp;&nbsp;&nbsp;🌟&nbsp;&nbsp;&nbsp;Front-end Development&nbsp;&nbsp;&nbsp;🌟&nbsp;&nbsp;&nbsp;HTML & CSS&nbsp;&nbsp;&nbsp;🌟&nbsp;&nbsp;&nbsp;JavaScript&nbsp;&nbsp;&nbsp;🌟&nbsp;&nbsp;&nbsp;Responsive Design&nbsp;&nbsp;&nbsp;🌟&nbsp;&nbsp;&nbsp;E-Commerce Solutions&nbsp;&nbsp;&nbsp;🌟&nbsp;&nbsp;&nbsp;SEO Optimization&nbsp;&nbsp;&nbsp;🌟&nbsp;&nbsp;&nbsp;Digital Marketing&nbsp;&nbsp;&nbsp;🌟&nbsp;&nbsp;&nbsp;Web Hosting&nbsp;&nbsp;&nbsp;🌟&nbsp;&nbsp;&nbsp;Content Management&nbsp;&nbsp;&nbsp;🌟&nbsp;&nbsp;&nbsp;Website Performance&nbsp;&nbsp;&nbsp;🌟&nbsp;&nbsp;&nbsp;Website Maintenance&nbsp;&nbsp;&nbsp;🌟&nbsp;&nbsp;&nbsp;Branding&nbsp;&nbsp;&nbsp;🌟&nbsp;&nbsp;&nbsp;User-Centered Design&nbsp;&nbsp;&nbsp;🌟&nbsp;&nbsp;&nbsp;Cross-Browser Compatibility&nbsp;&nbsp;&nbsp;🌟&nbsp;&nbsp;&nbsp;Website Security&nbsp;&nbsp;&nbsp;🌟&nbsp;&nbsp;&nbsp;Mobile Optimization&nbsp;&nbsp;&nbsp;🌟&nbsp;&nbsp;&nbsp;Conversion Rate Optimization&nbsp;&nbsp;&nbsp;🌟&nbsp;&nbsp;&nbsp;Site Speed Optimization";
  startMarquee('marquee-text-curved', 'text-path-curved', textContent, 2);
});
body {
  background-color: #0d0d0d;
  padding: 0;
  margin: 0;
}

.elementor-svg-marquee {
  width: 100% !important;
  height: 100vh !important;
  display: block;
  margin: 0 auto;
  padding: 0 !important;
  overflow: hidden;
}

.uppercase-text-curved {

  fill: #FFFFFF;
  font-size: 2rem !important;
}

text {
  font-size: 2rem !important;
}

/* Outer border for the stroke */
.curved-path-border {
  stroke-width: 6.1rem;
  /* Simulates the border */
  stroke: #2fb7d9;
  /* Border color */
  fill: none;
  filter: drop-shadow(0px 0px 5px #2fb7d9);
}

/* Actual stroke */
.curved-path {
  stroke-width: 6rem;
  /* Slightly smaller than the border */
  stroke: black;
  /* Stroke color */
  fill: none;
}

@media (max-width: 768px) {
  text {
    font-size: 4rem !important;
  }

  .curved-path-border {
    stroke-width: 8.1rem;
  }

  .curved-path {
    stroke-width: 8rem;
  }
}

@media (max-width: 480px) {
  text {
    font-size: 2rem !important;
  }

  .curved-path-border {
    stroke-width: 6.1rem;
  }

  .curved-path {
    stroke-width: 6rem;
  }
}
<div>
  <svg class="elementor-svg-marquee" viewbox="-50 0 1300 300" xmlns="http://www.w3.org/2000/svg">
    <defs>
      <path 
          id="text-path-curved" 
          d="M -100 150 Q 200 -50, 400 150 Q 600 350, 800 150 Q 1000 -50, 1300 150" 
      />
    </defs>
    
    <!-- Simulated border --> 
    <path 
        class="curved-path-border" 
        d="M -100 150 Q 200 -50, 400 150 Q 600 350, 800 150 Q 1000 -50, 1300 150" 
    />
    <!-- Actual stroke -->
    <path 
        class="curved-path" 
        d="M -100 150 Q 200 -50, 400 150 Q 600 350, 800 150 Q 1000 -50, 1300 150" 
    />
    
    <!-- Scrolling text -->
    <text
        font-family="Rubik, sans-serif"
        class="uppercase-text-curved"
        text-anchor="middle"
        dominant-baseline="middle"
    >
      <textpath id="marquee-text-curved" href="#text-path-curved"></textpath>
    </text>
  </svg>
</div>


Solution

  • Neither <img> nor <svg> are permitted content for a <textpath>.

    You could arrive at a partial solution by building your own font.

    1. Create a font containing your star, making sure to give it a character code (Unicode value) in a private use area.
    2. Add a @font-face style rule which establishes a font-family name and a reference to your font file.
    3. Replace your emoji with <tspan></tspan> tags (permitted content for a <textpath>)
    4. Place your character between the <tspan></tspan> tags, probably by using an escape sequence for your character code.
    5. Add a textpath > tspan style rule specifying your font-family name.

    This would at least be an improvement on the emoji, even without any animated rotation.

    My research leads me to believe that while SVG does support animation generally, it cannot be applied to <tspan> elements.