I have very large conten (a lot of pictures). I want to use css3 transition transform.
I bind to touchmove event, and calculate new x position.
But I have issue: the position by x does not change smoothly on mobile (on desctop all ok).
Event Touch comes with delays.
I try hidde don't used content (vissability: hidden) its not help.
Try throttling how fast the event handler makes the changes. It's counter intuitive, but by slowing things down, you will make them appear faster. The touchmove events are firing incredibly fast, far faster than the refresh rate of the screen.
Ideally, you would use requestAnimationFrame to do that.
Or if that is too experimental for your taste, simply make sure you are not performing your event handler actions faster than 60 frames per second (1 event handler action every 1000/60 milliseconds, the screen's refresh rate). If you still have problems at 1000/60 milliseconds, try a slower rate. The frame rate of video is 30 frames per second. Something between 30 and 60 frames should look good.
So that looks like this:
var lastFrameTime;
var myTouchMoveHandler = function (e) {
var now = Date.now();
if (now < lastFrameTime + 1000/60) {
return;
}
// your event handler code afterward
// ...
// then update the lastFrameTime
lastFrameTime = now;
}
Related
I'm having a little trouble working with the linearRampToValueAtTime on a BiQuadFilter applied to a WebAudio.
The audio works ok, and the initial lowpass filter is applied.
Problem is, as soon as I use the linearRamp method to bring up the frequency, it seems to ignore the endTime parameter (or better, it's not time correctly).
Some code to explain it better.
Here's the instancing:
this.audioLoader.load( 'public/media/soundtrack-es_cobwebs_in_the_sky.mp3', buffer => {
this.sounds.soundtrack = new THREE.Audio(this.listener);
const audioContext = this.sounds.soundtrack.context;
this.biquadFilter = audioContext.createBiquadFilter();
this.biquadFilter.type = "lowpass"; // Low pass filter
this.biquadFilter.frequency.setValueAtTime(200, audioContext.currentTime);
this.sounds.soundtrack.setBuffer(buffer);
this.sounds.soundtrack.setFilter(this.biquadFilter);
this.sounds.soundtrack.setVolume(0.5);
this.sounds.soundtrack.play();
})
Until here, everything looks ok. The sound plays muffled as needed.
Then, after a certain event, there's a camera transition, where I want the sound to gradually open up.
As a endTime parameter, I'm passing 2 seconds + the internal context delta.
this.sounds.soundtrack.filters[0].frequency.linearRampToValueAtTime(2400, 2 + this.sounds.soundtrack.context.currentTime);
Expecting to hear the ramp in two seconds, but the sound opens up immediately.
What am I missing?
The linear ramp will be applied using the previous event as the startTime. In your case that will be audioContext.currentTime at the point in time when you created the filter. If that is sufficiently long ago it will sound as if the ramp jumps right to the end value. You can fix that by inserting a new event right before the ramp.
const currentTime = this.sounds.soundtrack.context.currentTime;
const filter = this.sounds.soundtrack.filters[0];
filter.frequency.setValueAtTime(200, currentTime);
filter.frequency.linearRampToValueAtTime(2400, currentTime + 2);
I'm working on a relatively complex animation in SwiftUI and am wondering what's the best / most elegant way to chain the various animation phases.
Let's say I have a view that first needs to scale, then wait a few seconds and then fade (and then wait a couple of seconds and start over - indefinitely).
If I try to use several withAnimation() blocks on the same view/stack, they end up interfering with each other and messing up the animation.
The best I could come up with so far, is call a custom function on the initial views .onAppear() modifier and in that function, have withAnimation() blocks for each stage of the animation with delays between them. So, it basically looks something like this:
func doAnimations() {
withAnimation(...)
DispatchQueue.main.asyncAfter(...)
withAnimation(...)
DispatchQueue.main.asyncAfter(...)
withAnimation(...)
...
}
It ends up being pretty long and not very "pretty". I'm sure there has to be a better/nicer way to do this, but everything I tried so far didn't give me the exact flow I want.
Any ideas/recommendations/tips would be highly appreciated. Thanks!
As mentioned in the other responses, there is currently no mechanism for chaining animations in SwiftUI, but you don't necessarily need to use a manual timer. Instead, you can use the delay function on the chained animation:
withAnimation(Animation.easeIn(duration: 1.23)) {
self.doSomethingFirst()
}
withAnimation(Animation.easeOut(duration: 4.56).delay(1.23)) {
self.thenDoSomethingElse()
}
withAnimation(Animation.default.delay(1.23 + 4.56)) {
self.andThenDoAThirdThing()
}
I've found this to result in more consistently smoother chained animations than using a DispatchQueue or Timer, possibly because it is using the same scheduler for all the animations.
Juggling all the delays and durations can be a hassle, so an ambitious developer might abstract out the calculations into some global withChainedAnimation function than handles it for you.
Using a timer works. This from my own project:
#State private var isShowing = true
#State private var timer: Timer?
...
func askQuestion() {
withAnimation(Animation.easeInOut(duration: 1).delay(0.5)) {
isShowing.toggle()
}
timer = Timer.scheduledTimer(withTimeInterval: 1.6, repeats: false) { _ in
withAnimation(.easeInOut(duration: 1)) {
self.isShowing.toggle()
}
self.timer?.invalidate()
}
// code here executes before the timer is triggered.
}
I'm afraid, for the time being, there is no support for something like keyframes. At least they could have added a onAnimationEnd()... but there is no such thing.
Where I did manage to have some luck, is animating shape paths. Although there aren't keyframes, you have more control, as you can define your "AnimatableData". For an example, check my answer to a different question: https://stackoverflow.com/a/56885066/7786555
In that case, it is basically an arc that spins, but grows from zero to some length and at the end of the turn it progressively goes back to zero length. The animation has 3 phases: At first, one end of the arc moves, but the other does not. Then they both move together at the same speed and finally the second end reaches the first. My first approach was to use the DispatchQueue idea, and it worked, but I agree: it is terribly ugly. I then figure how to properly use AnimatableData. So... if you are animating paths, you're in luck. Otherwise, it seems we'll have to wait for the possibility of more elegant code.
I was wondering how to handle the fact that an interrupted transition within d3.js does not trigger an end event. As the API doc says
Note that if the transition is superseded by a later-scheduled
transition on a given element, no end event will be dispatched for
that element; interrupted transitions do not trigger end events.
from: https://github.com/mbostock/d3/wiki/Transitions#control
In my case transitions are triggered by user interaction. These transitions might be interrupted when the user triggers a new transition through mouse click. Let's say in the first transition an element was meant to fade out and be removed at the end of the transition. If this transition is interrupted the element will never be removed. I could disallow further user interaction during the time a transition happens yet that is not really what I want (particular as i have back and forward buttons which allow the user to click through previous states of my svg graph quickly ... ) Basically I would need an "Interruption Event"
Thanks
martin
I think there is no really satisfactory way to do this. A little bit painful workaround would be counting the number of transitions currently taking place and reasoning from that.
So, initialize:
var transitionCount = 0;
And whenever you schedule new transitions:
if ( transitionCount != 0 ) {
// handle interrupted transitions here somehow
transitionCount = 0;
}
var myTransition = selection.transition().... ;
transitionCount += myTransition.size();
myTransition.each('end', function() { transitionCount --; });
If you can handle manually cleaning up interrupted transitions like this, this would be fine. Notice, that you can't use 'start' events to increment the counter as there is a delay between scheduling a transition and it being started so you'd get a race condition there.
I have written a small application that performs some long-running tasks. Instead of having the user to wait and seeing just a progress bar, I would like to display some (changing) information about the application.
For that purpose, I wrote the following code within the constructor of an extended Pane:
FadeTransition fadeOutTransition = new FadeTransition(Duration.millis(1000), this);
fadeOutTransition.setFromValue(0.8);
fadeOutTransition.setToValue(0.0);
Similarly the fadeInTransition. And further...
SequentialTransition seqTransition = new SequentialTransition (
new Transition() {
{ setInterpolator(Interpolator.DISCRETE);
setCycleDuration(Duration.seconds(1)); }
protected void interpolate(double frac) {
int nextElement = (int) ((explenations.size() - 1) * Math.random());
Explenation explenation = explenations.get(nextElement);
questionLabel.setText(explenation.getQuestion());
answerLabel.setText(explenation.getAnswer());
}
},
fadeInTransition,
new PauseTransition(Duration.seconds(15)),
fadeOutTransition
);
What I woud like is the text to fade in, stay there for ~15 seconds and then fade out again. Unfortunately, the animation flickers, moves faster and slower - and the PauseTransition never takes 15 seconds! What is wrong about the code? I'm using Java 7, and JavaFX 2.2 on Mac OS X.
The problem seems to be that I called the function
seqTransition.play();
multiple times. From there comes probably the flickering and the unequal waiting time.
Basically, I'm looking for all the events that happen as a swf is loading, getting starting, playing the first frame, etc. Ideally, I'd like it broken down by flash version....
I ran this code:
var events:Array = [
Event.ACTIVATE,
Event.ADDED,
Event.ADDED_TO_STAGE,
Event.CANCEL,
Event.CHANGE,
Event.CLEAR,
Event.CLOSE,
Event.COMPLETE,
Event.CONNECT,
Event.COPY,
Event.CUT,
Event.DEACTIVATE,
Event.ENTER_FRAME,
Event.EXIT_FRAME,
Event.FRAME_CONSTRUCTED,
Event.FULLSCREEN,
Event.ID3,
Event.INIT,
Event.MOUSE_LEAVE,
Event.OPEN,
Event.PASTE,
Event.REMOVED,
Event.REMOVED_FROM_STAGE,
Event.RENDER,
Event.RESIZE,
Event.SCROLL,
Event.SELECT,
Event.SELECT_ALL,
Event.SOUND_COMPLETE,
Event.TAB_CHILDREN_CHANGE,
Event.TAB_ENABLED_CHANGE,
Event.TAB_INDEX_CHANGE,
Event.TEXT_INTERACTION_MODE_CHANGE,
Event.UNLOAD
];
for each(var i:String in events)
{
addEventListener(i, _response);
}
function _response(e:Event):void
{
trace(e.type);
removeEventListener(e.type, _response);
}
And found that a few of the events initially dispatched include:
exitFrame
activate
enterFrame
frameConstructed
This only applies to the MainTimeline, but you can perform the same test on other automatically initialized entities as well.
Here is a list of events that happen when the first frame is about to be played: The MovieClip life cycle
Other than that, there are Loader specific events before that, if you are loading a swf from another one:
Event.INIT when the swf is ready to play. Event.COMPLETE when the download is complete.