Jump to content
Search Community

DrawSVG Set Position

Afrowave test
Moderator Tag

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

If you're looking to go from the start (or last clicked dot) to the clicked dot, you could use this:

 

let t1 = new TimelineLite({paused: true});
t1.from("#Trace_line", 10, { drawSVG: "0%" });

document.body.addEventListener("click", e => {
  var percent = parseFloat(mapDot.get(e.target.id)) / 10;
  TweenLite.to(t1, 2, {progress: percent});
});

 

  • Like 1
Link to comment
Share on other sites

Yes,

Thank you @ZachSaucier, this will do nicely. 

Is it possible to assign a starting point on the fly? I have tried to figure out how an SVG path starting point and curve/path direction is set and I have not seen anything in code. All I see is how to do that in Adobe Illustrator for a straight-forward SVG animation. 


Is it actually possible, short of re-orienting the SVG path afresh through javascript?

Link to comment
Share on other sites

1 hour ago, Afrowave said:

Is it actually possible, short of re-orienting the SVG path afresh through javascript?

Sort of. You can tween from middle values by using a fromTo, i.e. t1.from("#Trace_line", 10, { drawSVG: "50% 50%" }, { drawSVG: "0% 100%" }); 

 

So with your demo we can get the percentage of each circle and animate from the first click percentage to the later one:

 

See the Pen xxxKpaJ?editors=0010 by GreenSock (@GreenSock) on CodePen

 

Note that I changed your mapping function. I am not sure where you were getting the values that you had...

 

If you need to change the actual origin (i.e. where the wrapping point is; which one is "first") that's technically doable but a bit more complex. In GSAP 2 I think you'd have to change the actual path which wouldn't be fun.

  • Like 2
Link to comment
Share on other sites

Another idea: create individual paths from point to point and add them in an array. When two are clicked, create a timeline with Drawsvgs on the paths from point to point between them. Then tween that timeline.

 

Probably a better approach overall.

 

Sorry, on mobile now so I can't show you what I mean.

Link to comment
Share on other sites

This was on my mind, so here's some pseudo-code for the approach I mentioned in the last post:

 

var drawSVGs = [];
paths.forEach(function(path) {
  drawSVGs.push(/* new drawSVG tween for path, all going in same direction (clockwise or counter-clockwise) 
                probably with linear easing */);
});

// Optionally create another map (or array) of the "distance" of each path for improved duration and/or distance calculation

// Create a map of ID to index number
var IDMap = ...;

var firstIndex;
var state = 0;
function clickHandler(e) {
  if(state === 0) { // The "start from" click
    // reset
    TweenLite.set("circle", {fill: "#88ce02"});
    TweenLite.set("#Trace_line", {drawSVG: "0"});
    
    // Update values
    state = 1;
    firstIndex = IDMap.get(e.target.id);
    TweenLite.set(e.target, {fill: "#f00"});
  }
  
  else if(state === 1) { // The animating part
    state = 2;
    var secondIndex = IDMap.get(e.target.id);
    
    // This gets the distance based on index alone, which is fine if each path distance is
    // relatively the same. If you have an indication of the distance of each path the logic
    // is largely the same, you just have to add the distances instead of just calculating the
    // index differences.
    var clockwiseDistance = secondIndex - firstIndex;
    if(clockwiseDistance < 0)
      clockwiseDistance = drawSVGs.length - firstIndex + secondIndex;
    
    var counterClockwiseDistance = firstIndex - secondIndex;
    if(clockwiseDistance < 0)
      clockwiseDistance = firstIndex + drawSVGs.length - secondIndex;
    
    // optionally go the shortest path
    var tl = new TimelineLite({paused: true});
    if(clockwiseDistance < counterClockwiseDistance) {
      //for each index in the clockwise direction...
      tl.add(drawSVGs[i]);
    } else {
      //for each index in the counter-clockwise direction...
      tl.add(drawSVGs[i]);
    }
    
    // if you have the distances for each path, you could calculate the proper duration based on a
    // maximum like I did in the previous demo.

    TweenLite.to(tl, properTiming, {ease: yourEase, onComplete: function() { state = 0; }});

    TweenLite.set(e.target, {fill: "#00F"});
  } 
}

I hope that helps :) 

  • Like 1
Link to comment
Share on other sites

On 10/3/2019 at 4:23 PM, Afrowave said:

Is it possible to assign a starting point on the fly?

 

Just build the path on the fly.

https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths

 

Is this what you're going for?

 

See the Pen d1b65a87c5bb18ff6187680c036d24ac by osublake (@osublake) on CodePen

 

If you want curves, here's one way to do it.

 

See the Pen 862fc46fb3781fcc08ddfd7e5fa9f6f3 by osublake (@osublake) on CodePen

 

 

  • Like 3
Link to comment
Share on other sites

Quote

Note that I changed your mapping function. I am not sure where you were getting the values that you had...

Heheee, ?

 

I used the GSDevTools to read off the position at each point of the DrawSVG and hard-code them. I was doing that to as a think through process.

Link to comment
Share on other sites

Guys, guys ... ?

 

I was in the middle of working out something like what @ZachSaucier has proposed ...

 

let mapDot = { "Dot_1, Dot_2": "Trace-01", "Dot_2, Dot_3": "Trace-02" };
var max = 100;
var duration = 1;

TweenLite.set("path", { drawSVG: "0" });

var firstVal;
var secondVal;
var state = 0;
document.body.addEventListener("click", e => {
    if (state === 0) {
        // The "start from" click
        TweenLite.set("circle", { fill: "#88ce02" });
        TweenLite.set("path", { drawSVG: "0" });

        // Update values
        state = 1;
        firstVal = e.target.id;
        TweenLite.set(e.target, { fill: "#f00" });
    } else if (state === 1) {
        // The animating part
        state = 2;
        secondVal = e.target.id;
        TweenLite.set(e.target, { fill: "#00F" });
        line2Trace = firstVal + ", " + secondVal;
        traceLine = "#" + mapDot[line2Trace];
        myTween = TweenLite.to(traceLine, 1, {
            drawSVG: "100%",
            onComplete: function() {
                state = 0;
            }
        });
    }
});

I was looking at the generating the dot coordinates to allow a clockwise and counter-clockwise direction and adding a TimelineMax  that I could ti.add() to it. 

Only for @OSUblake to blow everything out of the water.  ?

 

Quote

Just build the path on the fly.

He says ... Thank you Blake. You have made me realise that I am not using my math as much as I should and getting beyond basic shapes and lines in SVG.

Let me get to work. I will definitely post my solution here. ?

Link to comment
Share on other sites

Hey @ZachSaucier and @OSUblake,

 

Thank you guys for being patient with this. I have got to the place where I am making multiple svg paths on the fly and I am able to set up the points that DrawSVG is meant to draw across.

But there is a hitch. It looks like I need to implement an "async - await" on the Tween that is drawing out the path, but I am not sure. What do you guys think?
 

See the Pen QWWLMvy?editors=0010 by Afrowave (@Afrowave) on CodePen

 

Link to comment
Share on other sites

2 hours ago, Afrowave said:

It looks like I need to implement an "async - await" on the Tween that is drawing out the path, but I am not sure. What do you guys think?

Do you mean to give it time to append the element? There's no need for async for that.

 

You simply need to use createElementNS instead of createElement. You should probably also give it the trace class. 

 

See the Pen oNNgbzG?editors=0010 by GreenSock (@GreenSock) on CodePen

  • Like 2
Link to comment
Share on other sites

Thank you @ZachSaucier !

 

I never knew about XML namespaces. My SVG know how is moving along very well, thanks to you.

I got Interesting glitch. I put in your code into mine and forgot to change the Tween target. What I have now is the linePath redrawing itself on every subsequent element click.  When I comment out the Tween, it then behaves like your code but the SVG being rendered by the browser based on the path information.

It looks very nice and looks exactly like what I want with the Tween and the wrong target. My problem is I can't understand how drawSVG is doing.

 

Link to comment
Share on other sites

2 minutes ago, OSUblake said:

You aren't using a valid target. Like this.

Thanks @OSUblake. Yes, I know and I have said so. The glitch is exactly what I want by the looks of it, not by how it works. The question is, why is the Tween involved in rendering of the SVG and yet there is no valid target?

Link to comment
Share on other sites

2 minutes ago, Afrowave said:

The question is, why is the Tween involved in rendering of the SVG and yet there is no valid target?

 

It's not involved. Delete that tween code, and it would still work the same. You're setting the d attribute, which makes the path visible.

  • Like 1
Link to comment
Share on other sites

  • 3 months later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...