What are the steps for creating animated text that follows the outline of an oval?

I am attempting to create a text animation around an oval shape, similar to the one shown below:

While I have found solutions for animating text in a circular pattern, I am experiencing issues when trying to adapt it for an oval shape.

Does anyone have any insight on how to achieve this effect? Your assistance would be greatly appreciated.

Here is the code snippet for creating the animation with a circle:

var radius = 200; // adjust to move items in and out
var fields = $('.carousel__item'),
  container = $('.carousel'),
  width = container.width(),
  height = container.height();
var angle = 0,
  step = (2 * Math.PI) / fields.length;
fields.each(function() {
  var x = Math.round(width / 2 + radius * Math.cos(angle) - $(this).width() / 2);
  var y = Math.round(height / 2 + radius * Math.sin(angle) - $(this).height() / 2);
  if (window.console) {
    console.log($(this).text(), x, y);
  }
  $(this).css({
    left: x + 'px',
    top: y + 'px'
  });
  angle += step;
});
.carousel {
  width: 400px;
  height: 400px;
  margin: 10px auto;
  position: relative;
  border-radius: 50%;
  animation: spin 60s linear infinite;
}

.carousel:hover {
  animation-play-state: paused;
}

.carousel:hover .carousel__item {
  animation-play-state: paused;
}

.carousel__item {
  text-align: center;
  width: 300px;
  position: absolute;
  animation: spin 60s linear infinite reverse;
  font-size: 1.4rem;
}

@keyframes spin {
  100% {
    transform: rotate(1turn);
  }
}

.carousel__item:hover {
  animation-play-state: paused;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="carousel">
  <div class="carousel__item">TEXTTEXTTEXT</div>
  <div class="carousel__item">TEXTTEXTTEXTTEXT</div>
  <div class="carousel__item">TEXTTEXTTEXTTEXT</div>
  <div class="carousel__item">TEXTTEXTTEXTTEXT</div>
  <div class="carousel__item">TEXTTEXTTEXTTEXT</div>
  <div class="carousel__item">TEXTTEXTTEXTTEXT</div>
  <div class="carousel__item">TEXTTEXTTEXTTEXT</div>
  <div class="carousel__item">TEXTTEXTTEXTTEXT</div>
</div>

Answer №1

If you want a simple solution without complex calculations, you can control the shape using width and height. The text will rotate around the border, creating either a circle (when width = height) or an ellipse (when height != width).

All you need is some JavaScript to set a different delay for each element.

var delay = 0,
  step = 5 / $('.carousel__item').length; /* 5 represents the animation duration */
$('.carousel__item').each(function() {
  $(this).css('animation-delay', -delay + "s");
  delay += step;
})
.carousel {
  width: 400px;
  height: 200px;
  margin: 20px auto;
  position: relative;
  border-radius: 50%;
  border: 1px solid;
}

.carousel__item {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  animation: 
    move-x 5s linear infinite, 
    move-y 5s linear infinite;
  font-size: 1.4rem;
}

.carousel:hover .carousel__item {
  animation-play-state: paused;
}

@keyframes move-x {
  0% {
    left: 0;
    animation-timing-function: ease-in;
  }
  25% {
    left: 50%;
    animation-timing-function: ease-out;
  }
  50% {
    left: 100%;
    animation-timing-function: ease-in;
  }
  75% {
    left: 50%;
    animation-timing-function: ease-out;
  }
  100% {
    left: 0%;
    animation-timing-function: ease-in;
  }
}

@keyframes move-y {
  0% {
    top: 50%;
    animation-timing-function: ease-out;
  }
  25% {
    top: 0;
    animation-timing-function: ease-in;
  }
  50% {
    top: 50%;
    animation-timing-function: ease-out;
  }
  75% {
    top: 100%;
    animation-timing-function: ease-in;
  }
  100% {
    top: 50%;
    animation-timing-function: ease-out;
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="carousel">

Answer №2

If you want to achieve this effect, you can utilize the offset-path property in modern browsers.

To generate the path of an ellipse, you can make use of this tool.

.carousel {
  position: relative;
  left: 300px;
  top: 100px;
}

.carousel__item {
  position: absolute;
  offset-path: path('M-200,0a200,100 0 1,0 400,0a200,100 0 1,0 -400,0');
  offset-rotate: 0deg;
  animation: elipse 4s linear infinite;
}

@keyframes elipse {
  0% {
    offset-distance: 100%;
  }
  100% {
    offset-distance: 0%;
  }
}

.carousel__item:nth-child(2) {
  animation-delay: calc(-4s * 1 / 8);
}

.carousel__item:nth-child(3) {
  animation-delay: calc(-4s * 2 / 8);
}

.carousel__item:nth-child(4) {
  animation-delay: calc(-4s * 3 / 8);
}

.carousel__item:nth-child(5) {
  animation-delay: calc(-4s * 4 / 8);
}

.carousel__item:nth-child(6) {
  animation-delay: calc(-4s * 5 / 8);
}

.carousel__item:nth-child(7) {
  animation-delay: calc(-4s * 6 / 8);
}

.carousel__item:nth-child(8) {
  animation-delay: calc(-4s * 7 / 8);
}
<div class="carousel">
  <div class="carousel__item">TEXTTEXTTEXT</div>
  <div class="carousel__item">TEXTTEXTTEXTTEXT</div>
  <div class="carousel__item">TEXTTEXTTEXTTEXT</div>
  <div class="carousel__item">TEXTTEXTTEXTTEXT</div>
  <div class="carousel__item">TEXTTEXTTEXTTEXT</div>
  <div class="carousel__item">TEXTTEXTTEXTTEXT</div>
  <div class="carousel__item">TEXTTEXTTEXTTEXT</div>
  <div class="carousel__item">TEXTTEXTTEXTTEXT</div>
</div>

Answer №3

The equation of an ellipse differs from that of a circle in having different radii for the X and Y axes. It's as simple as that!

var radiusX = 100; // adjust to move items in and out
var radiusY = 60;
var fields = $('.carousel__item'),
    container = $('.carousel'),
    width = container.width(),
    height = container.height();
var angle = 0,
    step = (2 * Math.PI) / fields.length;
fields.each(function() {
    var x = Math.round(width / 2 + radiusX * Math.cos(angle) - $(this).width() / 2);
    var y = Math.round(height / 2 + radiusY * Math.sin(angle) - $(this).height() / 2);
    $(this).css({
        left: x + 'px',
        top: y + 'px'
    });
    angle += step;
});
.carousel {
 width: 400px;
 height: 200px;
 margin: 10px auto;
 position: relative;
 border-radius: 50%;
 animation: spin 10s linear infinite;
}
 .carousel:hover {
 animation-play-state: paused;
}
 .carousel:hover .carousel__item {
 animation-play-state: paused;
}
 .carousel__item {
 text-align: center;
 width: 300px;
 position: absolute;
 animation: spin 10s linear infinite reverse;
 font-size: 1.4rem;
}
 @keyframes spin {
 100% {
 transform: rotate(1turn);
}
}
 .carousel__item:hover {
 animation-play-state: paused;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="carousel">
<div class="carousel__item">-</div>
<div class="carousel__item">-</div>
<div class="carousel__item">-</div>
<div class="carousel__item">-</div>
... (repeated lines)
<div class="carousel__item">-</div>
<div class="carousel__item">-</div>
<div class="carousel__item">-</div>
</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Steps for creating a new tab and refreshing the address bar with a different URL without having to reload the current page

I'm trying to create a functionality on my page where clicking a button will open a new tab with a modified URL, all without reloading the current page. Below is the code that I'm using when the button is clicked: function changeUrl(){ var pri ...

best way to return a function variable in JavaScript

Hey there, I've been working with react native and have run into a bit of an issue... const SignIn = () => { screensplash() fetch('http://api.megamouj.ir/api/v1/logincheck/', { method: 'POST', headers: { ...

The issue of `window.setTimeout` not functioning properly with Google Maps Marker/XML integration has been a persistent

I'm having difficulty displaying markers individually from my database by making them "fly in." Here's the Ajax call: $.ajax({ type: "GET", async: true, url: '<?php echo PATH;?>ajax/map_process.php ...

Showcasing pictures on ReactJS

I am currently working on developing an application to showcase images on my React webpage. These images have already been uploaded to a local folder. In order to integrate my React application with a NodeJS server and MongoDB, I connected the two. My goa ...

Limiting the space character in a password field with regular expressions in JavaScript

Currently, I am facing the challenge of implementing a RegEx expression on a property within a model on an MVC website that I am currently developing. While I understand the individual components of the expression, I am struggling to combine them effectiv ...

Leverage the variables' values to access property

There is a way to use this possibility: let eventSelected = "333"; let bestResult = result.personal_records[eventSelected]?.single?.best //like searching like this: result.personal_records.333?.single?.best However, when deali ...

Quickly deliver a text file to the user - API Controller C#

After spending several hours searching and struggling to prompt a download of a text file from the server to the User's machine, I've decided to seek help here. The function is located in an ApiController. public class LogViewerController : ApiC ...

Analyzing Date Strings Retrieved From a MySql Database

In my MySQL database, I have a relationship that stores dates as varchar along with other attributes. This is how it looks: Answers answerId answer questionId date I am working on a web application where the user can select a &apo ...

Alignment of containers on the same level in a horizontal direction

Looking to achieve horizontal alignment of div containers. The container on the left (with a blue border) may have a fixed height. The other two containers (with red borders) should be aligned horizontally to the left blue container regardless of its heigh ...

What is the process for inserting an image using nodemailer in Outlook?

I have been facing an issue while trying to send emails via Gmail using Nodemailer. The problem arises when the emails are opened on Outlook or Windows 10 Mail by the company, as I need to embed images like the logo and a background. While attaching the im ...

HTML Button to Populate Text in Textarea Box

I'm trying to figure out how to display HTML inside a textarea box for a link. I've managed to get it working perfectly, but I want it to show <a href="https://youtube.com">Link</a> instead of "Code for Link in HTML." Is th ...

Retrieve the matching values from a JSON object by filtering it with an array, then create a new JSON object containing only

var structureInfos = [{ name: 'HMDB0006285', identifier: 'Six two eight 5' }, { name: 'HMDB0006288', identifier: 'Six two double eight'}, { name: 'HMDB0006293& ...

Ways to eliminate line breaks in a specific script

I am brand new to using phonegap and I need some help figuring things out. Here is the script source: <script src="http://www.transfermate.com/en/exchange_rates_api.asp"></script> I am attempting to remove the s in the div 'currency_c ...

Keep one div attached to the edge of another div to ensure they remain conjoined when resizing

Is there a way to center a Square within the border of another div? I have attempted the following method: .container { position: relative; background-color: blue; } .square { position: absolute; height: 50px; width: 50px; border-radius: 0% ...

When an iteration occurs within a for loop and a value changes, remember to incorporate a line break or equivalent element using jQuery

I am currently working on implementing a hierarchy system for users stored in a database table. At the moment, only top-level users with a hierarchy of 1 are displayed. When clicked, I use AJAX to retrieve and display all related users below them. These ...

How to pass a String Array to a String literal in JavaScript

I need to pass an array of string values to a string literal in the following way Code : var arr = ['1','2556','3','4','5']; ... ... var output = ` <scr`+`ipt> window.stringArray = [`+ arr +`] & ...

Prevent lengthy headers from disrupting the flow of the list items

I've encountered an issue while working on a website that features a list of items. When the title, such as "roller blinds," spans across two lines, it disrupts the layout below. How can I prevent this from happening without compromising on having lon ...

What is causing the classList function to throw an error: Uncaught TypeError: Cannot read properties of undefined (reading 'classList')?

There's an error that I can't figure out: Uncaught TypeError: Cannot read properties of undefined (reading 'classList') console.log(slid[numberArray].classList) is working fine, but slid[numberArray].classList.add('active') is ...

Install Chakra UI in the latest Next.js project directory

Recently, I decided to incorporate Chakra UI v2.4.9 into my Next.js project running on version v13.1.6. To ensure a seamless integration, I followed the detailed instructions provided in Chakra UI's official guide for Next.js. However, I encountered s ...

Employ a CSS3 media query within a Sass @for loop

Is it really achievable? For instance: @for $i from 1 through 12 { @media screen and (min-width: #{$i * 240}) { width: {$i * 240 + (20*($i-1)) } ; } } However, the issue I'm facing is Invalid CSS after "...nd (min-width: ": expected expre ...