I'm pretty new to GSAP with Scrollmagic, was trying to do multiple tweens in one scene but couldn't figure out how so I ended up doing 3 scenes like this.
// init controller
var controller = new ScrollMagic.Controller();
// build scene
var scene1 = new ScrollMagic.Scene({
triggerElement: "#trigger1"
})
.setTween("#animate1", 0.4, {
opacity: 1,
left: 0
})
.reverse(false)
var scene2 = new ScrollMagic.Scene({
triggerElement: "#trigger1"
})
.setTween("#animate2", 0.4, {
opacity: 1,
left: 0,
delay: .4
})
.reverse(false)
var scene3 = new ScrollMagic.Scene({
triggerElement: "#trigger1"
})
.setTween("#animate3", 0.4, {
opacity: 1,
left: 0,
delay: .8
})
.reverse(false)
//.addTo(controller);
controller.addScene([
scene1,
scene2,
scene3
]);
Is there a way to simplify this code? I am looking to add more but I feel like there is a short way to write this?
Thanks in advance!
Final code
var timeline = new TimelineMax();
var tween1 = TweenMax.to("#animate4", .5, {
opacity: 1,
top: 0
});
var tween2 = TweenMax.to("#animate5", .5, {
opacity: 1,
top: 0
});
var tween3 = TweenMax.to("#animate6", .5, {
opacity: 1,
top: 0
});
var scene = new ScrollMagic.Scene({
triggerElement: "#trigger2"
});
//.addTo(controller);
//controller.addScene([
// scene4
//]);
timeline.add(tween1).add(tween2).add(tween3);
scene.setTween(timeline)
scene.addTo(controller);
You can use TimeLine to add multiple tweens to a scene
var timeline = new TimelineMax();
var tween1 = TweenMax.from("#animate1", 1, {opacity: 1, left:0});
var tween2 = TweenMax.to("#animate2", 1, {opacity:1, left:0, delay:0.4});
timeline.add(tween1).add(tween2);
scene.addTween(timeline);
If you want to have multiple items appear one after the other, you can use stagger
TweenMax.staggerTo(".myclass", 0.5, {opacity:0, y:-100, ease:Back.easeIn}, 0.1);
Related
I'm new to three.js and I'm using Tubegeometry of three.js in externalRenders of ArcGIS recently. I encountered a problem that the tube will have Strange jitter and distortion when I move the perspective, the situation will be exacerbated as the radius and length of the tube decrease. The gif below should be a good explanation of what happened:
I have been stuck with this for a few days,Can someone help me solve this?
Here's the complete javascript code:
let path=[
[116.533079,39.352741],
[116.533080,39.352753],
];
var map = new Map({
basemap: "satellite",
ground:'world-elevation'
});
var view = new SceneView({
container: "mapContainer",
map: map,
viewingMode: "local",
camera: {
position: [116.533079, 39.352741, 13154.641086300715],
fov: 55,
heading: 318.70623732061983,
tilt: 42.34234113203692
}
});
//create the reference line
view.graphics.add(new Graphic({
geometry:{
type:'polyline',
paths:path,
},
symbol:{
type: "simple-line", // autocasts as SimpleLineSymbol()
color: [226, 119, 40],
width: 2
}
}))
const myRenderer = {
view:view,
renderer:null,
camera:null,
scene:null,
height:100,
offset:0,
map:null,
setup:function (context){
this.renderer= new THREE.WebGLRenderer({
context:context.gl,
premultipliedAlpha:false,
});
this.renderer.setPixelRatio(window.devicePixelRatio);
this.renderer.setViewport(0,0,view.width,view.height);
this.renderer.autoClearDepth = false;
this.renderer.autoClearStencil = false;
this.renderer.autoClearColor = false;
const originalSetRenderTarget = this.renderer.setRenderTarget.bind(
this.renderer
);
this.renderer.setRenderTarget = function (target) {
originalSetRenderTarget(target);
if (target == null) {
context.bindRenderTarget();
}
};
this.scene = new THREE.Scene();
this.camera = new THREE.PerspectiveCamera();
const axesHelper = new THREE.AxesHelper(10000000);
this.scene.add(axesHelper);
// create the Tubegeometry
let v3List=[];
path.forEach((item)=>{
var renderPos = [0, 0, 0];
externalRenderers.toRenderCoordinates(view, [item[0], item[1], 100], 0, SpatialReference.WGS84, renderPos, 0, 1);
v3List.push(new THREE.Vector3(renderPos[0], renderPos[1], renderPos[2]));
})
console.log(v3List)
let curve = new THREE.CatmullRomCurve3(v3List, false);
let tubeGeometry = new THREE.TubeBufferGeometry(curve, 1, 10, 20, false);
var textureLoader = new THREE.TextureLoader();
this.map = textureLoader.load('img/point2.png')
this.map.wrapS = THREE.RepeatWrapping;
this.map.wrapT = THREE.RepeatWrapping;
this.map.repeat.set(2,20);
let material = new THREE.MeshBasicMaterial({
color: 0x85A9A9,
side:THREE.BackSide,
//map:this.map,
transparent: false,
depthWrite: false,
opacity: 0,
aoMapIntensity:0,
});
let tube1 = new THREE.Mesh(tubeGeometry, material);
this.scene.add(tube1);
let tubeGeometry2 = new THREE.TubeBufferGeometry(curve, 1, 10, 20, false);
let tubeMaterial2 = new THREE.MeshPhongMaterial({
color: 0x85A9A9,
side:THREE.FrontSide,
//map:this.map,
transparent: false,
depthWrite: false,
opacity: 0,
aoMapIntensity:0,
});
let tube2 = new THREE.Mesh(tubeGeometry2, tubeMaterial2);
console.log(tube2);
this.scene.add(tube2);
var ambient = new THREE.AmbientLight(0xffffff, 1);
ambient.position.set(0, 100, 0);
this.scene.add(ambient);
context.resetWebGLState();
},
render: function (context) {
const cam = context.camera;
this.camera.position.set(cam.eye[0], cam.eye[1], cam.eye[2]);
this.camera.up.set(cam.up[0], cam.up[1], cam.up[2]);
this.camera.lookAt(
new THREE.Vector3(cam.center[0], cam.center[1], cam.center[2])
);
this.camera.projectionMatrix.fromArray(cam.projectionMatrix);
this.map.offset.x += 0.001;
this.map.needsUpdate = true;
this.renderer.state.reset();
this.renderer.render(this.scene, this.camera);
externalRenderers.requestRender(view);
// cleanup
context.resetWebGLState();
}
}
externalRenderers.add(view, myRenderer);
})
This looks very much like the Precision Issues detailed in https://developers.arcgis.com/javascript/latest/api-reference/esri-views-3d-externalRenderers.html
As an experiment I want to animate a square with the Tween class and save all the frames as png files, however a proper callback such as onUpdate doesn't seem to exist. I would like to call it on every new frame and generate a png of the current state with a function I have already created or via another solution.
The code below is based on an example I found in this repository on Github.
let i = 0;
let tween = new Konva.Tween({
node: rect,
duration: 1,
x: 140,
y: 90,
rotation: Math.PI * 2,
opacity: 1,
strokeWidth: 6,
scaleX: 1.5,
onUpdate: () => { // does not exist
i++;
console.log(i);
render_frame(i);
},
onFinish: () => {
console.log("finished");
}
});
tween.play();
There is no onUpdate callback, but we can use the draw event of layer to save the image:
let tween = new Konva.Tween({
node: circle,
duration: 1,
x: 140,
y: 90,
rotation: Math.PI * 2,
opacity: 1,
strokeWidth: 6,
scaleX: 1.5,
onFinish: () => {
// remove draw event
console.log('finish');
layer.off('.tween');
}
});
tween.play();
layer.on('draw.tween', () => {
// save layer to image
console.log('to image')
})
https://jsbin.com/regiduzusi/1/edit?html,js,console,output
Update:
If you need synchronous updates you can change tween time manually.
const duration = 1;
const tween = new Konva.Tween({
node: circle,
duration: duration,
x: 140,
y: 90,
rotation: Math.PI * 2,
opacity: 1,
strokeWidth: 6,
scaleX: 1.5
});
const FPS = 25;
const tics = FPS * duration;
for (let i = 0; i < tics; i++) {
tween.seek(i / tics);
layer.draw();
console.log('to image')
}
Demo 2: https://jsbin.com/fudanozani/1/edit?html,js,console,output
This is my script for drawing an SVG path with ScrollMagic:
// Prepare SVG
function pathPrepare_journey($el) {
var lineLength_journey = $el[0].getTotalLength();
$el.css("stroke-dasharray", lineLength_journey);
$el.css("stroke-dashoffset", lineLength_journey);
}
var $journey1 = $("path#path1");
var $journey1_2 = $("path#path2");
var $journey1_3 = $("path#path3");
pathPrepare_journey($journey1);
pathPrepare_journey($journey1_2);
pathPrepare_journey($journey1_3);
// Reference to container
var container = $("#section1");
var containerHeight = $(container).height();
var vpHeight = $(window).height();
// Init controller
var SVGcontroller_journey = new ScrollMagic.Controller();
// Build tween
var tween_journey = new TimelineMax().add(
TweenMax.to($journey1, 1, { strokeDashoffset: 0, ease: Linear.easeNone })
);
// Build scene
var scene = new ScrollMagic.Scene({
triggerElement: container,
duration: containerHeight - vpHeight / 2,
tweenChanges: true
})
.setTween(tween_journey)
.addIndicators({
name: "Draw Journey Lines#1",
colorTrigger: "brown",
colorStart: "brown",
colorEnd: "brown",
indent: 600
})
.addTo(SVGcontroller_journey);
It works perfectly fine, but as you can see, I have three individual paths inside my SVG ($journey1,$journey1_2 & $journey1_3), and the ScrollMagic scene currently only draws one of them, $journey1, because I was only able to add that one to the TimelineMax().
My simple question: How do I add the other paths so they are drawn at the same time as $journey1?
I was able to add the other paths, but they are being drawn consecutively:
// Build tween
var tween_journey = new TimelineMax()
.add(
TweenMax.to($journey1, 1, { strokeDashoffset: 0, ease: Linear.easeNone })
)
.add(
TweenMax.to($journey1_2, 1, { strokeDashoffset: 0, ease: Linear.easeNone })
);
I figured out, that I can target paths by class inside the TweenMax timeline like so:
var tween_journey = new TimelineMax();
tween_journey.to(".cls-2", 1, { strokeDashoffset: 0, ease: Linear.easeNone });
This animates/draws all paths of the given class at the same time and hence solves my problem.
I want to know how you have the animation only play once going forward when you scroll down and when you scroll up there is no animation.
var controller = new ScrollMagic.Controller();
var tween_1 = TweenMax.to('#obj_1', 0.5, {
left: '0%', delay: .1
});
var containerScene = new ScrollMagic.Scene({
triggerElement: '#scene_1',
offset: -100
})
.setTween(tween_1)
.addIndicators()
.addTo(controller);
It's pretty easy actually, you set reverse:false as option, like so:
var controller = new ScrollMagic.Controller();
var tween_1 = TweenMax.to('#obj_1', 0.5, {
left: '0%', delay: .1
});
var containerScene = new ScrollMagic.Scene({
triggerElement: '#scene_1',
offset: -100,
reverse:false
})
.setTween(tween_1)
.addIndicators()
.addTo(controller);
So I have a for loop generating, placing and tweening 20 rectangles. However the code only destroys the last generated rectangle. Is there an (ideally simple) way to ensure that the .destroy() applies to every rectangle instead of the last one?
$("#combat").click(function() {
for (var i = 0; i < 20; i++){
var rect = new Konva.Rect({
x: -500,
y: stage.height()*Math.random(),
width: 480,
height: 20,
fill: 'green',
stroke: 'black',
strokeWidth: 3
});
layer.add(rect);
tween = new Konva.Tween({
node: rect,
duration: 1,
x: 500,
onFinish: function() {
rect.destroy()
}
}).play();
}
});
var tween = new Konva.Tween({
node: pentagon,
duration: 1,
x: 500,
onFinish: function() {
// this will be tween instance
// this.node will be rectangle
console.log(this.node);
}
}).play();
You can use Group object for this:
EDIT:
$("#combat").click(function() {
var rectGroup = new Konva.Group();
for (var i = 0; i < 20; i++){
var rect = new Konva.Rect({
x: -500,
y: stage.height()*Math.random(),
width: 480,
height: 20,
fill: 'green',
stroke: 'black',
strokeWidth: 3
});
rectGroup.add(rect);
layer.add(rectGroup);
tween = new Konva.Tween({
node: rect,
duration: 1,
x: 500,
onFinish: function() {
rectGroup.destroy()
}
}).play();
}
});