Creating dynamic SVG animations through CSS instead of relying on the <animateMotion> tag offer greater flexibility and control

I am attempting to position an arrow at the midpoint of a bezier curve. The method outlined in this StackOverflow question, which involves using <animateMotion> to move a <path> representing the arrow and freezing it at the center of the curve, only works in Firefox. Due to the frequent changes in my curve's points, I prefer not to use marker-mid as recalculating the midpoint each time is costly for me.

<svg viewBox="0 0 500 500">
<g>
    <path id="path1" d="M291.698 268.340 C321.698 268.340, 411.904 93.133 441.904 93.133"></path>
    <path class="path_arrow" d="M0,0 L6,6 L0,12" transform="translate(-3,-6)">
        <animateMotion dur="0s" rotate="auto" fill="freeze" keyTimes="0;1" keyPoints="0.5;0.5">
            <mpath xlink:href="#path1"></mpath>
        </animateMotion>
    </path> 
</g>
<g transform="translate(166.698,243.340)">
    <circle r="5" class="p1"></circle>
</g>
<g transform="translate(441.904,68.133)" >
    <circle r="5" class="p2"></circle>
</g>
</svg>

Is there a way to achieve this using CSS Animations instead of relying on <animateMotion> ?

EDIT 1:

The endpoints of the curve are draggable, causing the curve's points to frequently change. The goal is to animate the arrow to the center of the curve without manually calculating the midpoints. https://i.sstatic.net/RvBLV.png

EDIT 2:

Following Kaiido's suggestion, I added calcMode="linear" resulting in the arrow being correctly positioned along the path. However, when repositioning the endpoint by dragging, the arrow remains in its original position in Chrome instead of moving along with the parent path. This behavior is consistent with Firefox but not Chrome.

https://i.sstatic.net/VVOhy.png

Answer №1

If you want to achieve the same result using CSS, you can make use of the offset-path, offset-distance, and offset-rotate properties:

#path1 {
  fill: none;
  stroke: black;
}
.path_arrow {
  transform: translate( -3px, -6px );
  offset-path: path("M220 104C220 144,400 180,400 224");
  offset-rotate: auto;
  offset-distance: 50%;
}
body { background: white; }
<svg width="500" height="500" >
  <path id="path1" d="M 220 104 C 220 144 400 180 400 224"
        fill="none" stroke-width="2" stroke="black" />
  <path class="path_arrow" d="M0,0 L0,12 L12,6 z" />
</svg>

However, it's important to note that the browser support for these CSS properties is lower compared to SVG SMIL, as indicated by their browser support.

In case you need IE support, there is a JavaScript implementation available at this link, which appears to support <animateMotion> and rotate. Please keep in mind that this implementation hasn't been personally tested.



In reference to "EDIT 2" in the question:

It seems that Chrome requires an explicit call to update the <mpath>. This can be achieved by invoking the beginElement() method of the <animationMotion> element after each update:

document.querySelector('svg').onmousemove = function(e) {
  const rect = this.getBoundingClientRect();
  const x = e.clientX - rect.left;
  const y = e.clientY - rect.top;
  path1.setAttribute( 'd', `M ${x} ${y} C 220 144 400 180 400 224` );
  // Chrome requires an explicit update
  document.querySelector('animateMotion').beginElement();
}
<pre style="position: absolute; pointer-events:none">Move your mouse to change the path</pre>
<svg width="500" height="500">
  <path id="path1" d="M 220 104 C 220 144 400 180 400 224"
        fill="none" stroke-width="2" stroke="black" />
  <path d="M0,0 L0,12 L12,6 z" transform="translate(-3,-6)">
    <animateMotion dur="0s" rotate="auto" fill="freeze"
                   keyTimes="0;1" keyPoints="0.5;0.5" calcMode="linear" >
       <mpath xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#path1"/>
    </animateMotion>
  </path>
</svg>

Answer №2

To achieve the desired effect, make use of webkit animation in your CSS code. It is also highly recommended to explore resources like https://codepen.io/collection/yivpx/, which is a fantastic open-source project dedicated to SVG optimization. Additionally, remember to assign names to all classes within your SVG file for enhanced flexibility when applying CSS animations, such as using the following snippet:

animation: kaboom 5s ease alternate infinite;

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

The button is not centered within the grid container

I need assistance centering the button within a Grid layout using Material-UI <Grid container style={{backgroundColor:'green'}} alignItems="center" justify="center" > <Grid alignItems="center" justify=&q ...

What is the best way to automatically close a modal window after pressing the submit button

Having some trouble with my modal window using pure CSS. Can't seem to get it to disappear after clicking the submit button. Any suggestions on how to hide it properly? Here is the code snippet of both the HTML and CSS for reference. Open to all ideas ...

Is this an effective and appropriate method for establishing media queries?

<link id ="style" rel="stylesheet" type="text/css" title="other" href="regularStyles.css" /> <link rel="stylesheet" media= "all and (mid-width: 767px) and (max-width:2049px) and (min-height:767px) and (max-height: 1538px)" href="notePads.css" /& ...

Is there a way to condense a paragraph of text without using a span or div element?

There is a common scenario where I often encounter this issue: <span> <p>hello world</p> </span> It involves reducing the width of a paragraph to fit the text, but unfortunately it leads to clutter in my HTML. Is there a way to ...

The edge of the 'parent' element is obscured by the :after element

I am trying to create a transparent outlined button with a shadow in the shape of the button. However, I am facing an issue where the border of the button appears behind the :after element. You can see the problem below. Adding overflow: hidden to the tog ...

In the world of web design, blank areas can sometimes appear on a page as you

My website has a fixed header with a height of 44 pixels, content that takes up 89% of the screen, and a footer that occupies 6% of the space. Everything looks fine when the browser is at 100% zoom, but as I zoom out, white spaces start appearing before th ...

Is there a way to automatically refresh the page and empty the input fields after clicking the submit button on the contact form?

My knowledge of PHP and js is limited, so I may require additional guidance in incorporating those codes. Lately, I've been developing a contact form and making good progress. However, I'm struggling with figuring out how to refresh the page or ...

Exploring different ways to customize the grid style in Angular 6

Here is the style I am working with: .main-panel{ height: 100%; display: grid; grid-template-rows: 4rem auto; grid-template-columns: 14rem auto; grid-template-areas: 'header header''sidebar body'; } I want to know how to cha ...

Can someone tell me where I can locate the CSS file once I've finished using Scene Builder?

Currently, I am working on my database project using Scene Builder. I have applied some CSS styling and would like to locate the CSS file in order to attach it to my IntelliJ project for further code editing. Can anyone guide me on where to find the CSS ...

Is it possible to deactivate the onclick event following a successful ajax request?

I am looking to disable the onclick event after a successful ajax request. <div class="report_button" id="report_button" title="Reportthis" style="width:65px;height:15px;" onclick="reported_text(user_id,lead_id);">Report</div> This is the div ...

ID is not receiving the CSS styles

I'm having trouble applying my CSS to a specific img ID element on the page. I've been trying to solve this for about 30 minutes with no luck. The strange thing is, I have two other elements with the same HTML and CSS that are working correctly. ...

What is the suitable condition necessary for optimal functionality?

Greetings all! I am a newbie in the world of development and also new to Stack Overflow. This is my maiden post seeking assistance on the following issue: $(document).ready(function() { $(".header").click(function() { if ($(".header-content"). ...

organize multiple blocks in the middle of the page (html)

This code is unique and belongs to me. <html> <head><title>HOME||~All About EDM~</title> </head> <body > <center><img src="edm1.jpg" alt="edm" width="950" height="250"></body></center> <c ...

What is the procedure for adding a background to a primeNg Tree component?

Working with Angular CLI 6 and primeNg version 6.0.1 I have been attempting to customize the background of the tree component without success. When I try using style="background:red" in the HTML file, the tree display becomes distorted with a height of on ...

"Enhance Your Webpage with Textual Links that Display Background

A div with a background image is causing issues when links are placed on top of it. The links do not display the underline when hovering over them, unlike other links on the page. Below is the code snippet causing the problem: <div style="min-height:2 ...

Centered on the page vertically, two distinct sentences gracefully align without overlapping, effortlessly adjusting to different screen sizes

I had no trouble centering horizontally but I'm struggling with vertical alignment. I want these two sentences to be positioned in the middle of the page, regardless of device size. I attempted using vertical-align without success and then tried posit ...

Is there an issue with the CSS styling causing the IE7 button to not display correctly?

While testing my website in IE7, I noticed that the orange link box for create account is not displaying properly. The bottom of the orange rectangle appears to be cut off. Is there a CSS solution to fix this issue? If you have IE9, you can view this by go ...

Is it feasible to exclusively apply Twitter Bootstraps .navbar-fix-to-top on mobile devices?

I am working on a website using Twitter Bootstrap 3 and I have implemented the following navbar: <div class="col-xs-12 col-md-10 col-md-offset-1"> <nav class="navbar navbar-inverse" role="navigation"> <div class="navbar-header"> ...

Ways to expand the play and pause buttons and adjust the height of an HTML audio player

It's clear that the PLAY/PAUSE icons are smaller than intended, and the entire player is thinner than desired, making it difficult for some viewers to see. How can I enlarge the entire player? I have read that we do not have access to individual contr ...

Matching an element that contains a specific string in JS/CSS

I'm currently faced with an HTML file that's being generated by an outdated system, making it tricky for me to control the code generation process. The structure of the HTML code is as follows: <table cellpadding=10> <tr> ...