What is the best way to create an animated, step-by-step drawing of an SVG path

I am interested in creating an animated progressive drawing of a line using CSS with SVG/Canvas and JS. You can view the specific line I want to draw here

<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg">
 <!-- Created with custom SVG code -->
 <g>
  <title>Layer 1</title>
  <path d="m33,104c1,0 2.1306,-0.8037 23,3c9.07012,1.65314 10,2 24,2c7,0 29,0 33,0c8,0 9,0 11,0c2,0 8,0 11,0c9,0 17,0 18,0c10,0 12,0 20,0c1,0 6,0 7,0c2,0 3.07613,0.38268 4,0c2.61313,-1.08239 2,-3 2,-6c0,-1 0,-2 0,-3c0,-1 0,-2 0,-3c0,-1 0,-2 0,-3c0,-1 0,-2 0,-3c0,-1 0.30745,-3.186 -1,-5c-...
 </g>
</svg>

Answer №1

There are three methods outlined in this solution:


An innovative approach using SVG involves adjusting the stroke-dasharray to progressively increase the length of the 'dash' followed by a large gap.

Live Demo:

Key code snippet:

var distancePerPoint = 1;
var drawFPS          = 60;

var orig = document.querySelector('path'), length, timer;
orig.addEventListener('mouseover',startDrawingPath,false);
orig.addEventListener('mouseout', stopDrawingPath, false);

function startDrawingPath(){
  length = 0;
  orig.style.stroke = '#f60';
  timer = setInterval(increaseLength,1000/drawFPS);
}

function increaseLength(){
  var pathLength = orig.getTotalLength();
  length += distancePerPoint;
  orig.style.strokeDasharray = [length,pathLength].join(' ');
  if (length >= pathLength) clearInterval(timer);
}

function stopDrawingPath(){
  clearInterval(timer);
  orig.style.stroke = '';
  orig.style.strokeDasharray = '';
}

Alternatively, an all-SVG method allows you to construct the SVG path element step by step:

Live Demo:

Relevant code excerpt:

// Assumes 'orig' and dup' are SVG paths
function addNextPathSegment(){
  var nextIndex   = dup.pathSegList.numberOfItems;
  if (nextIndex<orig.pathSegList.numberOfItems){
    var nextSegment = orig.pathSegList.getItem(nextIndex);
    var segmentDup  = cloneSVGPathSeg( dup, nextSegment );
    dup.pathSegList.appendItem( segmentDup );
  }
}

function cloneSVGPathSeg( path, seg ){
  switch(seg.pathSegTypeAsLetter){
    // Cases for various path commands
  }
}

For a different approach, consider drawing the path onto an HTML5 canvas by sampling points along the SVG path and rendering them on the canvas:

Live Demo:

Relevant code snippet:

function startDrawingPath(){
  points = [];
  timer = setInterval(buildPath,1000/drawFPS);
}

// Assumes that 'orig' is an SVG path
function buildPath(){
  var nextPoint = points.length * distancePerPoint;
  var pathLength = orig.getTotalLength();
  if (nextPoint <= pathLength){
    points.push(orig.getPointAtLength(nextPoint));
    redrawCanvas();
  } else stopDrawingPath();
}

function redrawCanvas(){
  clearCanvas();
  ctx.beginPath();
  ctx.moveTo(points[0].x,points[0].y);
  // Draw the path on the canvas
  ctx.stroke();
}

Answer №2

There is a similar question that has been answered here.


I utilized your path and incorporated it into the code provided in the mentioned answer.

Check out the jsfiddle demo here

Here's the HTML code snippet:

<html>
<style>
    #canvas
    {
    border-style:solid;
    border-width:1px;
    }
</style>
<div id="canvas"> 
    <p>Hover over me</p>        
</div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>

And below is the JavaScript code snippet:

$(function() {
// Code for animating line will go here...
});
  • The path from the [d] attribute was extracted and assigned to the pathString variable.
  • A line defining the [stroke-width] was also added.

Although I have only dabbled with Raphael briefly, exploring examples and dissecting code structure (especially from page source) can provide valuable insights (I referenced the stroke-width placement from the page source of this example).


For more information on Raphael, you can visit their site here.


Just for fun, I created my own path as well. You can check it out here.

Answer №3

After discovering Phrogz's fantastic technique, I successfully crafted a simple yet effective GreenSock animation using TweenLite to smoothly transition from one length value to the getTotalLength() value.

As showcased in the demo, integrating this with a tween engine grants you extensive control while requiring minimal code.

const originalPath = document.querySelector('path');
let currentLength;
let timer;

const obj = {
  length: 0,
  pathLength: originalPath.getTotalLength()
};

originalPath.style.stroke = '#f60';

const tween = TweenMax.to(obj, 10, {
  length: obj.pathLength,
  onUpdate: drawLine,
  ease: Linear.easeNone
});

function drawLine() {
  originalPath.style.strokeDasharray = [obj.length, obj.pathLength].join(' ');
  updateSlider();
}

Kudos to Phrogz for the incredible concept and code contributions.

Access the CodePen demo here!

Answer №4

Last year, I embarked on a project involving animating a drawing using canvas. The paths consisted of SVG-type paths containing curves and lines, allowing me to easily extract them from the SVG file and insert them into a JavaScript array.

Check out this link for more details:

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

Next.js - utilizing dynamic API routes within nested folders

Currently, I am working on developing a basic API that reads a local JSON file. My goal is to create a dynamic API that can adjust based on the specific calls it receives. Within my API folder structure, I have: api --book ---[id].js ----content -----[id ...

Adjust the height of a DIV element using Jquery Resizable to a minimum height of 1px, smaller than its default value

Having an issue with the Jquery UI Resizable functionality. I've implemented Jquery resizable to adjust a div's width and height dynamically. It's been working well, but I'm encountering a problem when attempting to decrease the height ...

Creating unsightly class names using Node.js

Is it possible to automatically create random and unattractive class names? For example, is there a tool or plugin that can substitute the .top-header class with something like .a9ev within my CSS code? It would also be ideal if the class name in the HTML ...

Steps for Integrating a Web Service Reference in NodeJS

Can a Web reference be added to a NodeJS project similar to how it's done in .NET framework Web API Projects? Essentially, the NodeJS API project will serve as a middleware between the Front End and an XML Web service. The XML Web service is a secure ...

Tips for implementing a default font on a website

I've incorporated a unique font into a specific section of my website design, but I'm aware that this particular font may not be available on most of my users' computers. Is there a method to apply this font to selected text without resortin ...

What's the best way to add vertical space to my DIV containing buttons?

Here is an example of HTML with CSS classes that float elements left and right: <div class="block-footer"> <button class="medium float-left">A</button> <button class="medium float-left">A</button> <button class="m ...

Exploring the Ways to Share sessionStorage Across Multiple Browser Tabs Using JavaScript

I have recently started exploring client-side data storage and have successfully implemented an onkeyup search function. The goal is to retrieve the city name via AJAX and display it at the top within the header of the page. To store the city name, I have ...

Customizing WordPress using CSS overrides in the Pinboard theme

I'm currently customizing a WordPress theme for my website (pinboard theme) and so far, it's been an amazing experience. One of the features of this theme is a built-in slider/carousel. However, I am looking to change the title of the slider from ...

What is the best way to deactivate a hyperlink of an <a> tag specifically for a particular child within an element?

Imagine you have a clickable container that leads to another page when clicked. However, there are elements within this container that you want to disable so that clicking on them does not activate the link. How can this be achieved? For instance, ...

Continuously encountering the "Uncaught Error: Bootstrap dropdown requires Popper.js" message despite having already added popper.js to the code

Recently beginning my journey with Angular and Bootstrap, I decided to create a simple "hello world" app. I've included all the necessary libraries, but I encountered an error that has me stuck. Error: Bootstrap dropdown requires Popper.js I' ...

Tips on avoiding the accumulation of event handlers when dealing with click events triggered by the document selector in jQuery

I am currently working on a project that involves using AJAX to load various pieces of HTML code. This is done in order to properly position dynamic buttons within each portion of the HTML content. In my case, I need to trigger click events on the document ...

When you hit a certain point on the website, the scrolling momentarily pauses

Upon refreshing the page and scrolling down, I notice that the website experiences a brief lag for a few milliseconds before continuing as normal. Oddly enough, this issue only occurs after refreshing the page. Any suggestions on how to resolve this? Th ...

Close button in Popover not functioning properly for SVG element

Concern I am facing an issue with a popover close button in this fiddle. The close button on the popover seems to work only once. Detailed Explanation My goal is to create SVG elements dynamically through Angular directives, and I want them to have Popo ...

What is the best way to use CSS in conjunction with a Master Page and a new content page, ensuring that the new CSS does not interfere with

Currently, I am working with an ASP.Net 4.5 website that incorporates a master page. The site utilizes a CSS file that is applied universally across all pages. Recently, I added a new page to the website which contains its own custom CSS specifically desig ...

Converting Cookies to Numeric Values in JavaScript: A Step-by-Step Guide

I'm currently developing a cookie clicker website and am encountering an issue with saving the user's score to localstorage when they click the "save" button. Here is what my code looks like: let score = 0; function addPoint() { score += 1; } ...

How can data be displayed in AngularJS/Json without using ng-repeat?

It seems like I am required to use ng-repeat in order to display the data, but I would prefer to avoid using it. angular: App.controller('aboutLongCtrl', function ($scope, $http) { $http.get('test_data/ar_org.json') .then(func ...

Struggling with UI-Grid's single filter feature when dealing with intricate data structures?

I'm currently working with UI-Grid and facing a challenge while applying a filter to some complex data using their single filter example. Initially, everything runs smoothly when I use simple selectors. However, as soon as I attempt to delve one level ...

Utilizing Node.js to Retrieve Data from MySQL

Hi there, I'm new to NodeJS and I'm curious about how to fetch a MySQL query like we do in PHP. $query = mysql_query("SELECT * FROM accounts"); while($fetch = mysql_fetch_array($query)) { echo $fetch['Username']; } How would this be ...

What is the method for retrieving the locale value from the configuration in Next.js?

How can I retrieve the i18n.defaultLocale value from my Next.js app configuration? I thought it would be simple, but I'm struggling to find a clear solution for accessing the config settings in Next.js. Is there a specific built-in method for this, or ...

Verify that each interface in an array includes all of its respective fields - Angular 8

I've recently created a collection of typed interfaces, each with optional fields. I'm wondering if there is an efficient method to verify that all interfaces in the array have their fields filled. Here's the interface I'm working wit ...