Problem with SVG path not behaving as anticipated in animation

I found a helpful video tutorial on inline SVGs that I am using as a reference. My goal is to recreate the effect of an SVG line appearing to draw itself from its middle point outwards. The method described in the video involves setting the stroke-dasharray property to '0, length/2' and the stroke-dashoffset property to '-length/2', starting the line at its middle point. However, the challenge arises for me because my SVG line length is variable, unlike the predefined length in the video.

The technique seems simple: create an SVG line, set initial properties, and then adjust them when needed. In theory, changing the dasharray and dashoffset should make the line appear to draw itself from the middle outwards. But when I tried this with lines of unknown lengths, the line started drawing from almost the beginning instead of the middle. I used JavaScript to calculate the line length dynamically. Below is a snippet of my code.

function animateLine() {

  const input = document.querySelector('.input');
  const line = document.querySelector('.focus');
  
  const length = line.getTotalLength();
  
  line.style.strokeDasharray = `0, ${length/2}`;
  line.style.strokeDashoffset = `-${length/2}`;
  
  input.addEventListener('focus', function() {
    line.style.strokeDasharray = `${length}, 0`;
    line.style.strokeDashoffset = `0`;
  });
};


animateLine();
/* Input module */

.input {
  background: none;
  border: none;
  width: 100 %;
  padding: 0.5em;
  padding-left: 0;
  color: white;
  font-family: inherit;
  font-size: 0.85em;
}

.input:focus {
  outline: none;
}

.line {
  width: 100%;
  height: 2px;
  padding: 0;
  stroke: grey;
}

.focus {
  stroke: black;
  transition: all 5s;
  stroke-dasharray: 0, 10000;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <input class="input" type="text" name="review[body]" placeholder="Leave a review..." required>
  <svg xmlns="http://www.w3.org/2000/svg" class="line" viewBox="0 0 40 2" preserveAspectRatio="none">
                        <path d="M0 1 L40 1"></path>
                        <path d="M0 1 L40 1" class="focus"></path>
</svg>
</body>

</html>

I experimented with different approaches, like percentages and fixed values, but couldn't solve the issue. Could anyone provide insight into what might be causing the problem?

Answer №1

After some investigation, I have identified the issue. It may be a bit embarrassing, but I've decided to keep it here for anyone else who might encounter a similar problem.

The problem stemmed from my usage of "transition: all 5s" to assist in visualizing the midpoint while animating my SVG line. The issue arose because initially, I set the stroke-dasharray to "0, 10000" to hide the line, without setting the stroke-dashoffset property as I believed I needed to determine the midpoint first. Subsequently, I adjusted these two properties using JavaScript, which inadvertently triggered a 5-second transition. Consequently, when I interacted with the input element, the animation did not start from the desired midpoint; there was no delay upon loading the page, leading to an insufficient duration for the initial animation to reach the midpoint.

This confusion predominantly arose from my misunderstanding. I mistakenly assumed that the length of the SVG line was directly correlated to the size of the containing div (given I had set the width of the 'line' class to 100%). However, SVG sizes are actually determined using viewport units, rather than pixels or other fixed units. This realization led me to a simpler solution devoid of JavaScript. By focusing solely on the initially set viewport units and disregarding the actual displayed size of the SVG, the browser inherently adjusts these units proportionally based on available space. Therefore, instead of calculating the SVG path length, I can simply use a width of 20 viewport units as the midpoint of the SVG line, knowing these units will adjust relative to the available space within the SVG. It's worth noting this approach applies universally to any line length, as long as a 40 viewport unit is utilized.

/* Input module */

.input {
  background: none;
  border: none;
  width: 100%;
  padding: 0.5em;
  padding-left: 0;
  color: black;
  font-family: inherit;
  font-size: 0.85em;
}

.input:focus {
  outline: none;
}


/* SVGs */

.line {
  width: 100%;
  height: 2px;
  padding: 0;
  stroke: grey;
}

.focus {
  stroke: black;
  transition: all 2s;
  stroke-dasharray: 0, 20;
  stroke-dashoffset: -20;
}

.input:focus~.line .focus {
  stroke-dasharray: 40;
  stroke-dashoffset: 0;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <input class="input" type="text" name="review[body]" placeholder="Leave a review..." required>
  <svg xmlns="http://www.w3.org/2000/svg" class="line" viewBox="0 0 40 2" preserveAspectRatio="none">
                        <path d="M0 1 L40 1"></path>
                        <path d="M0 1 L40 1" class="focus">
                        </path>
                    </svg>
</body>

</html>

That concludes the explanation. A fundamental oversight on my part.

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

How can I get my HTML DIVs to automatically move downward instead of upwards?

I'm currently developing a chat script that includes the feature to minimize specific chats, but I've encountered an issue with making the header of the div push down. Despite researching extensively, I haven't been able to find a solution t ...

Obtain the "CSwitch" value within the CoreUi React framework

I am trying to figure out how to retrieve the value of a component called "CSwitch" <CSwitch name={element.Field} color={'primary'} variant='opposite' shape='pill' onChange={e => console.log(e.t ...

Embedded script displayed as textual content

I have HTML elements that are stored as a string and inserted into a webpage using AJAX with the jQuery method replaceWith(). The string contains a <div> element and an inline <script> that operates on it. The jQuery command I am using looks so ...

Enhancing Javascript functionality with additional on.change customization opportunities

My website currently has a dynamic AJAX script that updates a table based on the selection from a dropdown menu with the ID of [id="afl_player_ID"]. However, I am looking to extend this functionality so that the same script runs when either [id="afl_playe ...

Can a CSS class be designed to have a value that changes dynamically?

Let's say we have some div elements that look like this: <div class="mystyle-10">Padding 10px</div> <div class="mystyle-20">Padding 20px</div> <div class="mystyle-30">Padding 30px</div> Would it be possible to c ...

Assist me in minimizing redundant code in a basic jQuery function

I successfully created a carousel using the jQuery cycle plugin with 4 links that correspond to different slides. Currently, I have separate blocks of code for each link, but I'm looking to optimize by creating a single function. $('#features-sl ...

Out of nowhere, jQuery suddenly fails to recognize that my checkbox has been selected

http://pastebin.com/r30Wfvi3 Out of the blue, all that functionality suddenly ceased. var showMyLocation = document.createElement('input'); showMyLocation.type = "checkbox"; showMyLocation.className = "checkboxForRange"; showMyLocation.id = "sh ...

How can we implement programming logic for a Threejs Particle System that includes connecting lines between particles

I recently inquired about connecting nearby particles in ThreeJS and managed to create lines between them. However, due to the logic of the particle system, the lines are drawn twice. This behavior is similar to how the original 2D particle system function ...

Guide on disabling a hyperlink in a table column under specific conditions using Angular2

I am working with a table that has 4 columns: Name, id, Dept, City. The row data and column data are provided as an array from a typescript file and I am iterating through *ngFor to display the content. Below is a snippet of my code: <tbody> < ...

Transform JSON into CSV format and save the file for download

My task involves fetching a JSON object from a URL and converting it to a CSV file for download by the user. I need to create a button with an onClick function that will call the API, retrieve the JSON object, convert it to CSV, and enable the user to down ...

When using MongoDB, the client.open() function may return an error stating "undefined is not a valid function."

Here is my code snippet: var express = require('express'); var MongoClient = require('mongodb').MongoClient; var Server = require('mongodb').Server; var app = expre ...

req.login doesn't seem to be authenticating the user

My goal is to use Ajax to send a post request to the server without refreshing the page by using e.preventDefault. I want the server to check if the username or email is already taken, and if not, automatically log the user in and refresh the page. However ...

Preventing setTimeout from repeating upon reload in Angular

I have a dataset and processing code shown below: LIST = [{ "id": "1lqgDs6cZdWBL", "timeUpdated": "2020-04-22 12:51:23", "status": "CLOSED" }, { "id": "C2Zl9JWfZHSJ& ...

Propagating numerical values through iterative iterations

I am currently facing an issue with passing values as props to a component using the forEach method in JavaScript. In addition to passing the existing values from an array, I also want to send another value that needs to be incremented by 1 for each iterat ...

Importing specific modules in ES6 when defining an asynchronous component

I am looking to asynchronously load certain elements of my web app: Here is the original import code: import {Popover, PopoverButton, PopoverPanel} from '@headlessui/vue' export default { components: { Popover, PopoverButton ...

Execute JavaScript function on click event in NextJS

Is it possible to execute a JavaScript function on the client side without using addEventListener? This situation works with addEventListener. MyComponent.js import Script from 'next/script' export default function MyComponent({ props }) { ...

Tips for integrating search functionality with vanilla javascript?

My contact list app displays contact details and I am looking to add a search feature based on the contact's name. This functionality will allow the user to dynamically filter the contact list as they type in a specific name. Here is a snippet of the ...

problem with concealed picture when hovering cursor

While I know this issue has been discussed before, I am facing a slight confusion regarding displaying an image on MouseOver. Currently, I have a div container with a colored background that shows when hovered over. You can see an example of this here - sc ...

What steps are required to start running Karma once it has been installed?

I'm experimenting with using karma for various watch processes. To start, I globally installed karma by running: npm i -g karma After that, I executed karma start karma.conf.js and it ran successfully. Now I want to install karma locally within th ...

What is the best method for transferring data from a submit form in ReactJS to AdonisJS?

Seeking guidance on integrating a ReactJS form with an Adonis API to pass data upon form submission. Snippet from ReactJs file: async handleSubmit(e) { e.preventDefault(); console.log(JSON.stringify(this.state)); await axios({ ...