Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...

Julius Friedman

Members
  • Posts

    31
  • Joined

  • Last visited

Posts posted by Julius Friedman

  1. 11 minutes ago, GreenSock said:

    No. I'm not sure why you'd think that. The purpose of the snap function is to run logic every time the pointer moves when dragging, so that it can apply any snapping necessary at that point. 

     

    I'm not really sure what I'm looking for, but I see 3 different sliders. I assume you're talking about the bottom one maybe? I can drag it just fine all the way up and down. 

     

    It would be amazing if you could provide a very reduced test case without all the custom code in there - just the most basic thing you can possibly provide that demonstrates the issue. Hopefully less than 20 lines of code total would be ideal. Thanks so much!

     

    Yea but one snap should only ever be called per movement right? If I snap I should never call the snap function again? right? I should just be able to rotate the FOV except for the most extreme cases but we are digressing...

    What custom code is in the snapFunction pen?

     

  2. The CS is not open source YET, that is something I am cooking up maybe...

    It shouldn't be in the pen and if you see it let me know but I just checked and I didn't see it... Perhaps cached somehow... Not sure...

     

    If the snapFunction runs more than one time there is something wrong no?.... regardless of x or y or xyz, a snap to a single axis across any dimension would technically be acceptable if you need two snaps you should have two separate functions or the function should call that snap function with the information for the axis...

     

    I am going on another tangent... :p

    Let me know what I can do to better assist you with this issue. As you can see in the pen with the snap function I can get to index 3 by my setValue but can you ever drag the handle and get to all index's for both input and change?

    If so just modify / fork the pen and my apologies.

    Regards...

  3. 1 hour ago, marya said:

    I don't mind the hijacking, but since this edgeResistance thing is a new, different issue, it's better to just start a fresh post so that people can look at it separately. So yeah, good idea to do that.

     

    Anyway, I'm not a GS dev, so I am not going to try to look into Julien's issue further (sorry, I got my own troubles! ?). I wanted to see if it might be related to my issue, but since I can't reproduce it locally, I don't think that's it. Julien, I have no doubt this is happening to you, and it does seem like potentially a bug, but it also seems tricky to reproduce. Since you yourself found it did not occur on another device, it will be helpful to get more details about the differences between your two devices for the GS devs.

     

    FWIW, I currently believe my own issue is a race condition between the Draggable default onClick handling and my framework's onClick handling. So I'm pursuing the tactic of trying to get Draggable's onClick to handle all the needed clicking in my game. I hope it can be made to work. I will certainly post back here with any results.

    Right on, Didn't mean to intrude, just saw your example / demo and thought I could point a few things out so I hoped that helped.

    Upon noticing an issue in my other example I revised this and wanted to see if it was having an issue I was having and that's how I noticed the edgeResistance, I don't use the edgeResistance either right now so I just wanted to point that out.

     

    Indeed it's weird that it happens on this computer which is well equipped yet not with a laptop which is meager in comparison.

     

    Yes, the difference is the OS IMHO but the environment is just running GSAP right? It should work in all environments right?

     

    I definitely understand your points on the timing issue and I certainly agree there seems to be some funky logic there; especially on my system and the most we can do is document that and try to reliably replicate it so that GSAP can be a better product.

     

    My bad if stepped on any toes and what not, just trying to get the bottom of things.

     

    Good luck and let me know if theres anything I can do to help!

  4. 7 minutes ago, Dipscom said:

    Let us not hijack Marya's thread with this issue. She's has a rather quirky issue herself that I am also trying to replicate without luck so far. It's best not to mix things up.

     

    Have you got another thread going on about draggable? If you do, send me a link to it and we'll continue there. If you don't, create one and we'll go to town with it there.

    Not sure what you mean, I was editing my post and I got a call and then something else happened I didn't mean to HiJack, I just updated the pen with that users issue.

     

    Please take a look at that because I feel it's related and if not in this pen:

    See the Pen NQOaLx by juliusfriedman (@juliusfriedman) on CodePen



    On my windows 7 machine there is definitely an issue, onPress is fired and so is onInit but not onClick.

     

    And I do apologize for all the editing and confusion, I have a lot going on right now.


    I am going to take a break again... maybe until tommorow.

     

    Hopefully that will give you guys some time to look into this further.

  5. Looking at this just because I am pretty sure the math in my example is correct...

    See the Pen NQOaLx by juliusfriedman (@juliusfriedman) on CodePen

     

    I did some debugging and it seems that only onPressInit and onPress are ever fired again but for some reason there are no listeners attached to the object.

    a.listeners is empty {} in the minified code.

    I modified the example to just log on press and click, please see the pen.

     

    Verify this put opening up chrome and putting a break point on the `ka = `function which is basically the function which is raising the events. You will verify there that the callback is never executed by stepping the code.

     

    After you guys look into this please take a look at my little dragger example and let me know if that's related to this same issue or not.

     

    Thank you.

     

    • Like 1
  6. 16 minutes ago, Dipscom said:

    Don't get me wrong, I am not doubting there's an issue here but it's not as clear cut as "it's a bug in draggable" because, as said before, four people have tried, only one is getting the issue.

     

    Like it or not, we have to focus on your setup first and foremost to try and figure out what is going on.

     

    I know it sounds far fetched and I understand it works once you set edgeResistance to zero the problem goes away. I could be such an obscure thing...

     

    Did you try it in a incognito window? Just for the sake of ruling that out?

     

    Well the issue started out the same way, all I did was adjust the code to only use the GSAP Draggable and this is what I found...

     

    Honestly no, I hadn't; but I just did and the same thing happens. If you would like a screen capture I can provide one.

     

    This has nothing to do with my PC as I have another and I just tried the same thing there to make sure I am not going crazy... It's a HP laptop and on that machine it DOES NOT happen.


    It seems to be resolution / DPI related possibly and the hitTest combined with the edgeResistiance as I previously stated where the loop goes through the client values to offset them for the values in the event.

     

    Let me know what I can do to help you guys find the root cause as I am quite sure this has nothing to do with my machine configuration / settings and I would love to be proved wrong.

     

    It's also interesting to me because I am also having some positioning issues but when using snaps... Probably not related but who knows.

     

    Btw, not to hijack, but if your curious of the issue I was having you can check out 

    See the Pen BXgaqO by juliusfriedman (@juliusfriedman) on CodePen


     

    • Like 1
  7. 4 hours ago, marya said:

    Hey Julien, I browsed to

    (please verify the link) and I don't see the issue you mentioned with edgeResistance. Please double-check? I'm using a desktop computer with a mouse for testing this. I went straight to the pen and dragged the div off to the right halfway across the page. When it popped back its container, I clicked it, and it responded by showing 1 click, 2 clicks, 3 clicks, etc.

     

    Yes, in this pen I see the exact same issue as I captured in screen shot. Let me know if you need me to setup a Hangout or something so you can see first hand. The exact URL is 

    See the Pen NQOaLx by juliusfriedman (@juliusfriedman) on CodePen

  8. 12 minutes ago, Dipscom said:

    It could potentially be that, yes.

     

    It's likely it is going to be something like that. An extension or something extra in his machine as now four people have tested and only one seem to be having the issue.

     

    Obviously you guys have never used ScreenToGif... This has nothing to do with my machine or extensions...

    I was just trying to show you guys the issue...

    Here is another screen capture... (slightly too large so I have to link to it)
     

    https://giphy.com/gifs/dyingERq65yvQn4Xoc/fullscreen

     

    You will see there I reload multiple times and do the same thing quite easily.

     

    If i just change the edgeResistance then the problem goes away....

  9. 5 minutes ago, Dipscom said:

    It could potentially be that, yes.

     

    It's likely it is going to be something like that. An extension or something extra in his machine as now four people have tested and only one seem to be having the issue.

    I doubt it as I don't run any extensions and I was just recording the screen with Screen2Gif which shows the clicks for demonstration purposes...

  10. 37 minutes ago, marya said:

    I also used Chrome 76.0.3809.100 (Official Build) (64-bit) and did pretty much what you did, no problems. This is very weird.

    Why does your pointer glow when clicking?

     

     
     

    It doesn't it's for demonstration purposes. ScreenToGif does that via an option you can configure.

    • Like 1
  11. 26 minutes ago, GreenSock said:

    I couldn't replicate the issue you reported either, @Julius Friedman. Seemed to work fine for me. 

    See the Pen NQOaLx by juliusfriedman (@juliusfriedman) on CodePen



    I am using Google Chome, 76.0.3809.100 (Official Build) (64-bit)


    Go that that pen and drag the blue outlined box outside of the rectangle and let go when it's position is outside of the box.


    It will then snap back to inside the the other box.

     

    You can still drag and drop but you won't fire any more press or click events.

    pen.gif.9064217cd83a0839f5250b93131e3cc0.gif

    If you guys need a screen cast I have attached.

     

  12. Here is a pen @ 

    See the Pen BXgaqO by juliusfriedman (@juliusfriedman) on CodePen



    This pen contains the improvements I spoke of above.


    I gave up trying to use the snapIndex which didn't exist and I just tried to do things like were available in the library. (And not because my change didn't work but because I want to show you I am willing to learn if I can)

     

    You will see that because of the way the call was bound in the calling script I can't even bind my own context because the wall `call` is used to force the context...

     

    The logic to run the snap function specifies the context...


    `return a.call(Ha,e>c?c+(e-`

    Thus my snap function will always have the scope of the dragger? Except when called from a dragging event, then the scope is the callbackScope...

    This means I have to adjust my code to always use call when I am calling the snap function and I would also need the dragger instance to which it was bound...

     

    That is slightly awkward as I have given a callback scope and I have bound the function yet surprisingly enough it is called with it's own scope. This means I have to call it from that same scope or determine the scope from the function call...

     

    The only problem it seems at this point is that I can't approach the 0 boundary...

    If you look at the pen and drag the dragger you will see the values in the console, I seem to get the values right for 4, 3, 2 and 1 but the zero boundary is eluding me for some reason right now...

     

    In the lower slider there are only values 1 and 0 to make it easier.

     

    It seems the snap is working correctly but how to correctly calculate the index is eluding me right now...

     

    You will see for the slider with 2 options it works as expected but with 4 options I can't access index 3.


    The pen is at 

    See the Pen BXgaqO by juliusfriedman (@juliusfriedman) on CodePen

     and I am taking a break.

    I am pretty sure that is something with my math though and not your libraries code, specifically @ getSnap where I am probably not understanding how to handle the edge cases...

    That logic has been extrapolated here for review:
     

    function getSnap(endValue) {
                if (false === Number.isFinite(endValue)) return;
                const max = this.vars.type === 'x' ? this.vars.bounds.maxX : this.vars.bounds.maxY;
                if (endValue >= max) return max;
                const min = this.vars.type === 'x' ? this.vars.bounds.minX : this.vars.bounds.minY;
                if (endValue <= min) return min;            
                const mean = this.vars.mean;            
                return CS.context.Math.round(endValue / mean) * mean;
            };

     

    Please do let me know if you see something wrong with that.

    You can move the slider manually with code like

     

    range.setValue(3, true)

     

    You will notice that I can get to the correct position that way...

    However when snapping I can't, I run into values 0, 1, 2 and 4 but never 3 and in other examples there are also holes but not 0 and 1....

     

    I am going to step away for a bit as I can do nothing else outside of rewrite the logic or go back to using snaps like I was at this point.

    Please do let me know if you see anything as this resolution will relate to how my isTweening questions follow.

     

    I just updated the pen to log more and check my math.

     

    See the Pen BXgaqO by juliusfriedman (@juliusfriedman) on CodePen



    I noticed that getSnap is sometimes called just as many if not more times then there are snaps in the array, this depend on the users movement but now I am questioning on if snaps as an array was a better design choice...

     

    It seems if the user exceeds the bounds and then comes back in bounds with or without pressing then it can make the issue worse as getSnap may be called more for an unknown reason....

     

    I think this is an issue with the way offset location are being determined to stop the movement when the cursor is outside the bounds but again I only have the minified code to look at.

     

    The important things to take away is that I can position the slider handle correctly with the setValue method, yet while I cannot when dragging especially when I perform awkward movements e.g. slow and then fast or circular especially when exceeding the bounds.

     

    This is easily replicate-able in the various pens I have so let me know if theres anything that I can do better.

     

    I like that the snap function is more efficient but if it's going to be called more times than there are snaps in the sequence then it doesn't make sense for me or I imagine many others...

     

    We should only have to snap once and if the value exceeds the bounds at that point then the position is given by the min or max of the corresponding axis... Yes it's a little tricky at the bounds when dragging starts because theres nothing to compare to get a previous position to determine the direction so I think it also has something to do with timing as another user was saying but I am even more so confident that my is right for the application and that the problem lies somewhere in Draggable at this point.

     

    One confirmed point is that when the position is at the awkward  one and you put a break point, the snap function runs and returns the same value as it did previously however after that breakpoint the element's position can be seen to be changed but the snap function was not called again... 

     

    Thus I definitely think this is something to do with timing and how the event mechanism for clicks is able to run one more than 1 thread and sometimes that thread has an event which cannot be canceled and thus Draggable thinks that the event was cancelled yet the browser still has av event dispatched in that state.

     

    I am quite sure you know all about how events are implemented in browsers so I will leave it at that but if you happen to see something wrong in my code please do punch me in the face :P

     

    Taking the rest of the night to chill as I really don't think there is anything I can do other than go back to using snaps and my hacked up Draggable to save a few cycles which I am hopeful is not the final resolution!

     

    Good luck and thank you in advance!

     

     

     

     

    Regards!

  13. I am building a simple range like control as shown in my pens.

     

    In order to try to use the tools I have and make the best component possible I am trying to refactor my logic to not require a snap array at all....

    This will allow me to only have to set the min and max values accordingly and then I can move the snapping logic to a function.


    A) The snap callback is always in the scope of the dragger, even if you have a callback scope. That threw me off at first but it seems it's by design and I believe it's probably correct, a person can bind the function for the scope they needed....

     

    B) In a snap function it seems my logic must be to replace the iterative approach of the snaps and just calculate the value, that should always be more efficient that looping so it seems like a better approach however I had the following issues...

     

    C) It seems that is the only way to know the value without looking it up without he snapIndex / snapAxis.

     

    1) When using snaps the bounds are respected such that if the user exceeds the bounds the correct snap is chosen according to the direction of travel, when using a function you have to determine the direction of travel since your not running the iterative loop anymore. It also changes how you would react to the logic therein...

     

    2) It seems that sometimes the logic wraps for getting the snap e.g. if the bounds are small and the object is large or the object is moving then you also have to take into account hit testing in the snap function with respect to the movement and that complicates things a bit as well as you might have to call update as well as apply bounds and it doesn't help that update only takes a Boolean and not the new bounds...

     

    I am going to rework my math and logic see where I can get but I wanted to make sure that this is the correct approach and that I am understanding things correctly.

     

    Let me know if you need a pen to better understand.

     

     

     

     

  14. 6 hours ago, GreenSock said:

    It's probably more complicated than you'd expect. It seems your statement was based on the assumption that start/end values are always stored cleanly in the vars object, but that isn't the case. For example, a bezier tween may contain an array of values with nested x/y pairs (or any property). And there are many other examples like that. 

     

    Frankly, in all my years of doing this I can't remember anyone requesting this kind of functionality, nor have I needed it myself. Sure, there are times I may want to kill certain properties of a certain object from tweening, and that can already be accomplished with killTweensOf(). 

     

    I totally appreciate your thoughtful suggestions and they're not without merit. However, when developing a product like GSAP, it's always a difficult balancing act between packing in as much functionality as I can while keeping the file size down and the performance way up...oh, and trying to prevent the API surface area from expanding like crazy to the point where it's just confusing/overwhelming for end users. 

     

    I can't tell you how many times I've thought "well, in theory this feature might be cool..." or "oh, in this very specific use case, this feature would be nice to have..." and if I just keep cramming things in there, GSAP would end up becoming a monster. 

     

    It's certainly possible to add code to the core to allow you to getTweensOf(target, property), but I'm struggling to convince myself that more than 0.01% of users would ever actually tap into that and I'm not sure it's worth the added complexity, kb, etc. Others are certainly welcome to chime in - if we get a lot of requests for that type of thing, I'd definitely reconsider it. But again, in all my years of doing this (and over 8,000,000 sites using GSAP including most award-winnings sites), I can't remember anyone else asking for that type of functionality. (That doesn't mean it's without merit).

     

    Again, I sure appreciate the thought you've put into these posts and your desire to help us make GSAP even better. I'm working hard on GSAP 3.0 and I think you're gonna really like it. :) 

     

    With killTweensOf if there is a timeline is use or other tweens then you have to know which tweens your killing otherwise the timeline won't work anymore, this is more of a method to delay the an animation while another is taking place...

     

    Lets say I have a scenario where a user is dragging something and I want to create an effect for the drag such that I also have an animation for the drop.

    If the drop animation causes something to hide then I must manually keep state such that if the user drags and drops again I show the object and and then hide it again, this gets more complex if I am showing something like a status text or score and I don't want the drag to effect the existing display until the animation is done or I want to truncate that next animation and replace it with a new one which is more up to date....

     

    It would sorta of be able to be achieved using a behavior function and the onStart / onComplete but I would need a bit of a framework to accurately wrap it up and I am also assuming that since you know your code better than I do that I would be easier for you to accommodate....

     

    The objects to modify are passed directly to the engine and stored in vars of a tween or timeline? I am not seeing where it gets that dirty that it becomes a problem especially for someone who knows the architecture / API.

     

    I would also imagine that since the engine offers things like lag smoothing and all of those advanced features then it only makes sense to expose them in a way which the user can also use and take advantage of...

     

    E.g. if the engine knows it will skip a bunch of frames then it can also better choose which animations to animation if there were things like a priority and if that priority came from things like usage / requests to the property (which is also mathematically useful, e.g. how far along a tween is, when it will complete, etc).

     

    It just seems natural to me to take advantage of a good engine with good features and TweenMax's scheduler seems to be just that.

     

    The math you guys already do to determine things like proper ratio and spacing is quite good and I feel that if there is not something already useful for Sequencing besides the OnStart / OnComplete then perhaps it eventually makes sense to create something general for users to:

     

    1) save memory / cycles

    2) have consistent api / approaches / performance

    3) be able to stagger / stack animations according to performance / load

    4) take advantage of performance counters related to a tween (e.g. if I find scaling and rotation doesn't work that well I can switch in runtime)

    etc.

    5) allow users to react to tweens without having the vars, without events you can only have a single function as the entry point for the callbacks unless you dispatch on the element (and there is not always an element to dispatch on... proxies etc)

     

    The framework itself is mostly already there and the additions would be similar to adding / changing the features like you do now IMHO...

     

    When I get further along with some of my project / examples perhaps I can post the code to highlight how some of this would be useful if you really don't think it's important.

    Here are some potential use cases which are slightly different

     

    If I move something relatively but I want to cap the movement at a position / bounds I would need to combine onStart / onComplete and onUpdate, take into account the screen size / element position and transforms. Whereas if there was a better format for properties (perhaps similar to how the new CSS Unit stuff is being done...) I could write x: {minValue: 0, maxValue: 10, value: 'center, begin, end, top, bottom', unit: 'default, px, vw, etc'} specifying in the tween that the min / maxValues of x will be as well as what the value should be tweened to and how they should change.

     

    I would take then tweens which are effecting value in the way I want and apply them to other objects as well...

     

    This allows to make an Effect e.g. like a Reveal or a Scale or a Explosion etc and then use that effect in multiple places and on multiple objects yet change it with respect to performance.

     

    I can stack the Scale with the Exploding such that if 2 are occurring then I can have less of a pronounced effect etc.

     

    I have a user interaction which causes particles when pressed and a final effect on release, if the user rapidly presses the button the tween will occur in the same way each time and potentially cause different load to the engine. Without the state / performance metrics from the engine I have to keep track for myself if I can or should pronounce the effect as well as when it should take place.

     

    E.g. if the effect is on it's way out and I start the tween again or start another tween to start the effect again then the drop animation will never complete unless I manually wait for it and time it such that the user CANNOT drag again while the animation is playing OR I must track the animation and elegantly truncate it to cause the new animation to play.

     

    GSAP already has features to smooth eases and timing from one ease to another and this seems like the most natural extension of those features I can imagine.

     

    If there are other ways to handle these types of things please let me know and I will give a shot at that methodology.

     

  15. Hey guys,

     

    Just playing around with things and I wanted you to notice something with @marya's example...

     

    edgeResistance: 0.35

     

    In my pen @ 

    See the Pen NQOaLx by juliusfriedman (@juliusfriedman) on CodePen

     it seems that edgeResistance causes some type of issue when the card goes out of bounds which results in subsequently clicks not being ever fired again...

    To replicate just browse to the pen and drag the card out of bounds and then try to click on it and you will see that there are no more click events being fired....

    If you change the

     

    edgeResistance: 0

     

    The problem goes away..

     

    So I have renamed my pen (edgeResistance issue).

     

    Interested to see why that happens but I only have the minified code..

     

    Seems like it is indeed a bug... The only thing I ever encountered like this was due to me having the minX and maxX properties opposite of what one would expect, the minX was greater than the maxX.

     

    Not quite sure why edgeResistance would do that but it seems to have something to do with the calculation for hit testing. 

     

    If I find anything else I will let you know!

    • Like 2
  16. Noticed that TweenMax.isTweening lets you determine if the engine is working on a tween for a given element.

    I have a question about direction and inital / end values of the tween; what I am w
    ondering is if you can determine what properties and in what direction the tween is going or some other type of state to go along with the tween besides tracking that yourself.

     

    The engine must have the start and end values (just as the user must also unless they are using relative properties)...

    e.g. you can look at the _gsTransform.x to determine what the x property is at the current moment but unless you keep very granular state you don't always know when or where you are in the transform, hence I was assuming I could get that from the tween however it's complicated as there may be multiple tweens playing and effecting the properties...

     

    e.g. if I have a timeline and it's playing than TweenMax.isTweening will return true for that object, I inspect the _gsTransform to sample the properties I need however it would be nice to have an indication at this point if the Tween is going in forward or reverse without having to call

    `TweenMax.getTweensOf()` and then looping the tweens which will effect the property... I would have to know which tweens I was looking for or at least what properties I was looking for to make a function like

    TweenMax.isTweening(t, 'opacity')

    TweenMax.isTweening(t, 'scale')

     

    Which I feel is many times more useful than isTweening because you might only care about a certain property....

    It seems like this would be efficient for the engine to handle as it already knows what is being tweened... It also doesn't seem like it's that complicated of a function to write on the basis on my point. You would just get the tweens for that element and look in the vars for the property being effected.


    I can take a crack at it and see what I can come up with but please do let me know if you need an example or how you think I should handle this / how you guys typically handle this.


     

    var tween = TweenMax.isTweening(t, 'scale');
    
    var oldComplete = tween.vars.onComplete;
    
    tween.onComplete = function(){ oldComplete(); }

     

    This would easily let you get the tween which is effecting the scale property, wait for it to be completed and then call your function. You could also expand this to check again for something tweening scale etc.

     

    If you agree then it seems the next logical step would be to add a `queue` function (optionally with labels) so you can then do something like:

    TweenMax.queue(TweenMax.to(el, 1, {scale: 0}))

    Which would queue the tween but only when there were no more scale operations... further options could also be allowed from there e.g. using a timeline etc..

     

    Hopefully I missed something but if not hopefully you agree that this would be another good enhancement!

    A few possible uses:

     

    1) Augment tweens in a timeline / user interactions such that if another interaction occurs or another animation plays you can more seamlessly choose when to pause / resume or truncate etc.

    2) Tell if something is on it's way to being hidden or a size or position or in advance what the end position / values will be (if not truncated etc), powerful when moving something relatively or running movement and scaling tweens separately due to 1)

    3) Determine where to augment without waiting for the tween, e.g. I'm no longer forced to separate function logic so granularity because I can easily determine if the logic required is still able to run, Powerful for stacked animations e.g. if I have multiple unused graphics I want to animate out but keep that amount within a tolerance I can much more easily do that without any other state. (e.g. when only 2 graphics are in use maybe the augmented animation will play much more heavily then when there are 10 graphics in use i.e. they will only scale until there is 2 left then they will morph).

     

    Let me know if that makes sense, I know I can probably achieve this by keeping small state objects around but since the engine already has the objects in memory as well as the resulting values in the to / from the tween it seems somewhat wasteful. It also seems to pair well to the way you can store information in the tween with set and it will store that value, this way I can . to, .from . whatever and {x:0, y: 0, { state:{ .... }}} and from the object in the state of the tween I can take intelligent action and then if I kept state as a reference I could access it from else where outside of the tween with no additional memory overhead...

     

    Hopefully that makes sense but I have been looking at a lot of code today... I am going to try and get some sleep.

     

    Sincerely!

    • Like 1
  17. Just perusing the forums and I noticed this thread.

    PointC already gave you solid advice but if your looking for a small function to help with that then you can also write a function to compose the result...

     

    const  callbackIfFunction = function callbackIfFunction(f, r, s) {
                try { return f && f.call ? f.call(s || f, r) : r; }
                catch (e) { return e; }
            },
    compose = function compose() {
                const e = arguments.length;
                let r = e > 0 ? arguments[0] : undefined, i = 0;
                for (; i < e; ++i) r = callbackIfFunction(arguments[i], r);
                return r;
            };

    Used like...

     

    compose('1.1', parseFloat, Math.floor)

    Or even something like this...

     

    compose(Math.random, console.log)

    Hope that helps!

  18. Just so I can be sure I am making sense I updated my pen and the Draggable code to show you what I mean...

    The pen is the same but the logic is updated to handle if there was a snapIndex available from the Plugin @ 

    See the Pen BXqdMv by juliusfriedman (@juliusfriedman) on CodePen



     

    const value = this.dragger.vars.snapIndex ? this.dragger.vars.snapIndex : this.dragger.vars.snap.y.indexOf(this.dragger.y);
                this.setValue(value);

     

     

    DraggablePlugin required the following modifications to facilitate this:

     

    /Simple function declaration to save having to write function(a){return a};
                        λ = function () { return this; },
                        //Not 100% sure what this function does but it might be useful to store the result.
                        MUL = function (a, d) { return a * d },
                        //nb and ob could likely be combined especially the logic for the loop...
                        nb = function (a, b, c, d) {
                            return null == b && (b = -A), null == c && (c = A), "function" == typeof a ? function (e) {
                                var f = Ha.isPressed ? 1 - Ha.edgeResistance : 1;
                                //Here snapResult could be stored
                                return a.call(Ha, e > c ? c + (e - c) * f : b > e ? b + (e - b) * f : e) * d
                            } : a instanceof Array ? function (d) {
                                for (var e, f, g = a.length, h = 0, i = A; --g > -1;) e = a[g], f = e - d, 0 > f && (f = -f), i > f && e >= b && c >= e && (h = g, i = f);
                                //Here this.vars.snapIndex = h tracks the index and axis but might be transformed?
                                    //snappedIndex and snappedAxis might be better names?
                                this.vars.snapIndex = h;
                                this.vars.snapAxis = 'y';
                                return a[h]
                            }.bind(Ha) : isNaN(a) ? λ.bind(Ha, a) : MUL.bind(Ha, a, d)
                        },
                        ob = function (a, b, c, d, e, f, g) {
                            return f = f && A > f ? f * f : A, "function" == typeof a ? function (h) {
                                var i, j, k, l = Ha.isPressed ? 1 - Ha.edgeResistance : 1,
                                    m = h.x,
                                    n = h.y;
                                //Here snapResult could be stored but we also check y?
                                return h.x = m = m > c ? c + (m - c) * l : b > m ? b + (m - b) * l : m, h.y = n = n > e ? e + (n - e) * l : d > n ? d + (n - d) * l : n, i = a.call(Ha, h), i !== h && (h.x = i.x, h.y = i.y), 1 !== g && (h.x *= g, h.y *= g), A > f && (j = h.x - m, k = h.y - n, j * j + k * k > f && (h.x = m, h.y = n)), h
                            } : a instanceof Array ? function (b) {
                                for (var c, d, e, g, h = a.length, i = 0, j = A; --h > -1;) e = a[h], c = e.x - b.x, d = e.y - b.y, g = c * c + d * d, j > g && (i = h, j = g);
                                //Here this.vars.snapIndex = i tracks the index and axis but might be transformed?
                                    //snappedIndex and snappedAxis might be better names?
                                this.vars.snapIndex = i;
                                this.vars.snapAxis = 'x';
                                return f >= j ? a[i] : b
                            }.bind(Ha) : λ.bind(Ha, a)
                        },


    I have tested the code to make sure it didn't interfere with anything in Draggable and that it works as expected.

    Let me know what you think in regard to my hack / modification as well as the possibility of exposing that same data directly from the plugin and also adding the state information like I was explaining... I can take a crack at doing that but it's less useful for me at the moment as I am not needing to cancel the events or stop the propagation at the moment.

     

     

  19. Definitely not my intent, was actually hoping that I was missing things but understood and that sounds good.

     

    What about snapIndex and snapAxis being tracked by the plugin? I would hate to waste cycles myself looking up the snapIndex when it's known in the code as well as the direction before the callback is invoked.

     

    The example above where I use indexOf to determine the snapIndex is what I am trying to just read from the vars of the plugin rather than have to call every callback especially since those events block.

     

    I'm half tempted to just modify the code to store the index and axis as it already looks them up to facilitate the feature but I run the risk of hacking.... ?

     

    Let me know if I can make that more clear as I'm sure it would improve perf for people especially when there are a lot of snaps, all I am essentially asking is that the snapIndex gets recorded in the vars of the dragger somewhere as state so I can read it rather than loop through all snaps again.

     

    snapAxis would be helpful there also if there are 2 directions in use (with different snaps) especially since you guys already determine the axis first and then the snapIndex.

     

    Finally if direction could be stored (couldn't definitely tell from the minimized code but I am pretty sure the direction is also known), that would save people from calling getDirection again.

     

    I will also definitely try to keep threads separate, the only other thing I was questioning at this time was how to composite morphs into the same canvas if I wanted to or how to access the underlying canvas used for morphing when canvas was specified but that's save for now as I have to finish up the other logic needed for the controls and I will revisit that and improve the morphFromTo logic later on.

     

    Let's focus on the draggable issue here which is that snapIndex and snapAxis should be stored after they are looked up so in the callbacks I can access them without doing the math / lookup again. If you can give snapDirection if you call it then that's also helpful.

     

    Thank you and Blake for the demos very much!

    In that example you guys don't look up the snaps after creating them, but I have seen others which use the snapIndex and to get it they calculate it each time just like I do using the x / y even though it was already previously created.

     

    Giving a function of snap if definitely an improvement but only half of the work because it would still need to be coupled to something to store the state for the snapIndex / snapAxis etc and yet before the snap function is called logic is already run to determine the axis at least and would have determined the snap but found a function and not an array.

     

    Let me know if I can be any more clear or if I am missing on how to retrieve that information from the plugin without looking it up every callback!

     

    Also... while looking into the other thread where someone was have an issue with double events due to how they were using the plugin as well as some of my own event handling needs I was wondering what you thought about having the event state machine more exposed or at-least the current event..

    This I thought would be enable one to use a single function for each of the events and simply switch on the type of event more similar to how vanilla code would be with e.type... The next step would be having a e.next so I can determine if there would be a next event and use possibly it's name or other state information to determine what that type of event is and act on it.

    If you needed to call dragEnd or facilitate press / click etc that would then be possible by taking the state into account as you would already have access via the completionScope etc, or you could simply just call the corresponding method needed e.g. drag, press etc.

     

    Let me know if you agree / disagree or I am missing something.

     

    RE the operators, it seems like it's a small change from +=, -= and the code is already there to support it, things like centering to an element are typically always half the width and height so *=0.5 or /= 2 would be better than having to make a function just to do such small things, then again the parsing of the string to get the values is probably just as slow...

     

    Thank you!

     

  20. I noticed the topic on Draggable and I just wanted to chime in FWIW.



    Just a quick question on why your using click? Click is pseudo event which is created by the browser after a mouse down and corresponding mouse up.

     

    If you change you code to use the pointer events then it will work with all types of input and not just clicks..
     

    adrag.addEventListener("pointerup", clickHandler);

    Then you can modify your click handler like this:
     

    if (dragger && dragger.isDragging) return;

    You should also store the dragger after you create it where you store nClicks like so:

     

     var nClicks = 0, dragger;

    Then assign it after you create arr...

     

    var arr = Draggable.create("#adrag", {
    ...
    
      dragger = arr[0];

    With those changes I don't see any double click issues.

     

    See the Pen NQOaLx by juliusfriedman (@juliusfriedman) on CodePen



    Also I wouldn't prevent the default as the object was just made draggable there, I would let GSAP handle the bounds with the bounds appropriate.

    If you need to preventDefault then you will also need to do so for the mousedown / pointerdown which precedes the click event to cancel it.

     

    Let me know if I can help further!

     

    You can see an example of how I used Draggable here: 

    See the Pen BXqdMv by juliusfriedman (@juliusfriedman) on CodePen



    That reduces your example to:

     

    var resetClicks = function () {
    			nClicks = 0;
    			showNumberClicks();
    		};
                var clickHandler = function () {
                if (dragger && dragger.isDragging) return;
    			nClicks++;
    			console.log("clicked " + nClicks);
    			showNumberClicks();
    		};
                var showNumberClicks = function () {
    			var el = document.getElementById("adrag");
    			el.innerHTML = nClicks + " click" + (nClicks === 1 ? "" : "s");
    		};
                var nClicks = 0, dragger;
    
    		var doOnLoad = function() {
    			var adrag = document.getElementById("adrag");
    			var arr = Draggable.create("#adrag", {
    				zIndexBoost: false,
    				cursor: "inherit",
    				type: "top,left",
    				force3D: false,
    				allowEventDefault: true,
    				allowContextMenu: true,
    				edgeResistance: 0.35,
    				bounds: "#container",
    				allowEventDefault: false,
    				throwProps: false,
    				liveSnap: false,
    				
    				onClick: function (event) {
                        clickHandler();
    				}
    				
                });
                dragger = arr[0];
    		};
    
    doOnLoad();

    Which has been verified here:

     

    See the Pen NQOaLx by juliusfriedman (@juliusfriedman) on CodePen

     

    And has no issues that I can tell..

     

    • Like 3
  21. Quick question on the Draggable plugin...

     

    The impetus for this is that I was creating to a Range type control which was supporting screen orientation change.

     

    The snaps in my control act as a way to associate a value to the range, thus I suppose I could just use a function but I wanted to address this; Hopefully the points are simple enough but if not let me know and I will get a Pen created.

    When not using a custom snap function but using the snaps and liveSnap array feature for example:

     

    Draggable.create(this.handleGroup, {
                        type: 'y',
                        bounds: { //this.track, would cause transforms from that elements positions..
                            minY: 0,
                            maxY: this.track.height.baseVal.value
                        },
                        liveSnap: true,
                        //Direction specified to prevent movement along the other axis, on orientation change this must be changed to match.
                        snap: { y: [] },
                        //throwProps: true,
                        minDuration: 1,
                        overshootTolerance: 0,
                        dragClickables: true,
                        callbackScope: this,
                        onPress: this.onDrag,
                        onDrag: this.onDrag,
                        onThrowUpdate: this.onDrag,
                        onThrowComplete: this.onDragEnd,
                        onDragEnd: this.onDragEnd,
                        onRelease: this.onDragEnd
                    });


    You guys already have a feature that if an Array is provided the best point is selected from that array based on the direction of the drag.

     

    What I find slightly annoying though and probably much more useful than you would think is that we don't record the last drag direction or the last snapIndex.

     

    When dragging is occurring or ending one has to lookup the snap to provide that index if it's needed, e.g if your using the snaps as positions to indicate value something like this would work:

     

    const value = this.dragger.vars.snap.y.length - this.dragger.vars.snap.y.indexOf(this.dragger.y) - 1;

     

    Thus is you have only one direction your supporting and the snaps are the same then you can change the type and call apply and your done for orientation change, however you need to provide a supporting property for the snap in that axis e.g. you had snap.y and now you need snap.x or vice versa, still easy enough to alias in the event handler and your still done.


    If you have more than one direction though you still need to determine the direction after it was already determined in the code...

     

    So thus my gripes are as follows:

     

    1) We don't record the snapIndex and the snapAxis in the vars, this causes users to have to repeat the same logic as the plugin just did to find the snap when it's needed.

     

    2) If multiple directions are supported but only 1 direction at a time, one needs to define the snaps without the axis property (x, y) and just use a plain array from the start for the snap / liveSnap property and not an object with (x and or y)

     

    3) If multiple directions are supported at the same time having the snapAxis which caused the snap from the plugin is much more efficient than again determining the direction and the snapIndex when it just was previously done.

     

    Personally I then use the height of the track combined with the max values to set the snaps for example I have 4 default options here but you could specify an arbitrary number.
     

                const point = this.track.height.baseVal.value / (CS.context.Number.isFinite(this.options.maxValue) ? this.options.maxValue : 4);
    
                //Erase any existing points...
                this.dragger.vars.snap.y.length = 0;
    
                //Put the snaps in the dragger at the calculated space.
                for (let i = this.options.minValue; i <= this.options.maxValue; ++i)
                    this.dragger.vars.snap.y.push(point * i);


    So I supposed I could do this with a function and base it on the width or the height but I would still need to look the direction up again when it was just done previously by the Plugin to raise the event.

     

    Let me know what you think or if there is already a way to get that information which I am somehow missing in the documentation.


    Also checkout 

    See the Pen mNzBpo by juliusfriedman (@juliusfriedman) on CodePen

     as I also had a question about relative properties...

     

    It seems that relative properties only work with "+" and "-" and I was wondering why "*" and "/" as well as "%" are not implemented, maybe even "^"?

    E.g. if I wanted to tween to the modulo of my elements x and the width of another element I would use '%' if I wanted to move in powers of the width I would use "^" etc.

    One can also pretty easily do this themselves I was just curious why not as I would have expected at least *= and /= to work, e.g. for when I want to move to a relative position but sometimes that position should be reset to 0 the *= works well, /= also lends itself well in the reverse where % and %= are more dependent but still useful.

     

    I could also imagine some type of syntax which allows properties and objects to be scripted but that is well beyond the scope of what I imagined would come out of this question, an example would be something like:

     

    "{width:'%=' + $1.width, x: '*=' + $2.x}"

    Which is saying to set the width of the object to the modulo of the first objects width and the current width, also set the x of the x to the 2nd objects's x position....

     

    Overall honestly not sure how much more useful that would be than just coding and calculating yourself  but the idea is whats important, and it would allow for adjusting positions quite easily especially those positions which are related to each other...

     

    About to head to sleep, if I think of anything else I will update this post.

     

    See the Pen BXqdMv by juliusfriedman (@juliusfriedman) on CodePen

  22. Here you go

    See the Pen jgeBGJ by juliusfriedman (@juliusfriedman) on CodePen



    I think that should be equivalent although the example is a bit contrived, its only really noticeable at the end when you morph back.

     

    I didn't think the morphSVG Hack was exactly a hack as it rectified the issue and reduced the number of errors in the console completely after use but non the less, I digress...

     

    For complete recognition of the issue I am attempting to describe I think we might need a SVG with 2 shapes e.g. a rect and a circle which are in different groups.

     

    If the morph is applied to a shape within the group then the group transform is not taken into account during the morph and it's position would not be with respect to the group, someone would have to manually position the morphed path either before or another the morphing starts.

     

    Hence why I was using scale to manifest the issue in these examples when in reality it might not be needed at all.

     

    If that is known and expected than it's fine, one would just have to determine their graphics don't have needless transforms and do the math to ensure their path coordinates have been transformed respective to the group they reside in. (which is why I call my example contrived)

     

    This was more of a hey, it would be cool if GSAP either could do this for us automatically (via option) or allow us to customize further with a function, it seems trivial to allow an option for transformDepth (to determine how far up) and a an optional function which would allow the resulting transform to be modified further.

     

    As I have already shown in my examples one can simply remove the group matrix or even take it a step further and apply those transforms to the paths or integrate those transforms into the point data.

     

    You guys already do a lot of work to provide options like xPercent and yPercent as well as support for transformOrigin with percentage based values so I just thought this would extend to that naturally and would otherwise be useful...

     

    As an example of how it could be useful given a Reflection scenario (like a mirror), lets say I have a an object and I want to show the reflection of the object but reversed and at a different scale and angle.

     

    Currently I would have to duplicate the object, transform it, position it and then create 2 morphs, one for the object and one for it's reflection, (Unless I did some use trickery, I suppose I could only morph the one and the reflection would then also morph however it would morph in exactly the same way)

     

    With this methodology I would only need to create the 1 morph and then apply it with the transformations of the 'reflection' to get both to morph in the same way but at angles respective to each if that makes sense.

     

    E.g. the main object is not rotated or scaled much but the reflection object is half opaque and rotated arbitrarily and at a different angle.

     

    There are other uses but they are even more complex and mostly benefit from re-using the morph and tweens rather than creating new ones.

     

    The color issue I also have worked around but thought it would also be a good enhancement since GSAP also already supports relative tweening with HSL, e.g. "hsl(+=0, +=0%, -=30%)", e.g. if you can say withOpacity(1, style) or better yet computeStyle(withClasses) to get a computed style of only the classes you want / will use. 

     

    Perhaps when I get more time I can work on a plug-in which offers those options unless you get around to it first.

     

    Let me know if that makes sense and thank you again for your assistance!

     

    Please do let me know if I can do anything else!

     

    Regards

     

    • Like 1
×