svg synced animate elements - animation

I need to animate 6 svg circles that are dynamically created 1s appart from each other.
They should start as a yellow gradient and fade out to a red gradient in 6s.
But instead of starting yellow when they are created, they take the value the first element has at that moment so they all end up showing the same synced animation.
This is what i'm doing:
var svgElem = document.getElementById('svgElem');
var svgDefs = document.getElementById('svgDefs');
var count = 0;
function createNewElement(){
var rnd;
rnd = Math.floor(Math.random()*6);
rnd = 0;
createRadialAnimation(count, rnd);
var circle = document.createElementNS(svgElem.namespaceURI,'circle');
circle.setAttribute('cx', 100+Math.floor(Math.random()*300));
circle.setAttribute('cy', 100+Math.floor(Math.random()*300));
circle.setAttribute('r', 10);
circle.setAttribute('fill','url(#grad'+count+')');
var animate = document.createElementNS(svgElem.namespaceURI,'animate');
animate.setAttribute('attributeName', 'r');
animate.setAttribute('from', '10');
animate.setAttribute('to', '10');
animate.setAttribute('repeatCount', 'indefinite');
animate.setAttribute('fill', 'freeze');
animate.setAttribute('dur', '6s');
animate.setAttribute('begin', rnd+'s');
circle.appendChild(animate);
svgElem.appendChild(circle);
count +=1;
if(count<6){
setTimeout(createNewElement, 2000);
}
}
function createRadialAnimation(num, rnd){
var radialG = document.createElementNS(svgElem.namespaceURI,'radialGradient');
radialG.setAttribute('id', 'grad'+num);
radialG.setAttribute('cx', '50%');
radialG.setAttribute('cy', '50%');
radialG.setAttribute('r', '50%');
radialG.setAttribute('fx', '50%');
radialG.setAttribute('fy', '50%');
var stop = document.createElementNS(svgElem.namespaceURI,'stop');
stop.setAttribute('offset', '0%');
stop.setAttribute('stop-color', 'rgb(255,228,129)');
stop.setAttribute('stop-opacity', '0');
radialG.appendChild(stop);
stop = document.createElementNS(svgElem.namespaceURI,'stop');
stop.setAttribute('offset', '100%');
stop.setAttribute('stop-color', 'rgb(211,90,67)');
stop.setAttribute('stop-opacity', '1');
radialG.appendChild(stop);
var animate = document.createElementNS(svgElem.namespaceURI,'animate');
animate.setAttribute('attributeName', 'stop-color');
animate.setAttribute('from', 'rgba(255,228,129,1)');
animate.setAttribute('to', 'rgba(211,90,67,1)');
animate.setAttribute('repeatCount', 'indefinite');
animate.setAttribute('dur', '6s');
animate.setAttribute('begin', rnd+'s');
animate.setAttribute('fill', 'freeze');
stop.appendChild(animate);
animate = document.createElementNS(svgElem.namespaceURI,'animate');
animate.setAttribute('attributeName', 'stop-opacity');
animate.setAttribute('from', '1');
animate.setAttribute('to', '0');
animate.setAttribute('repeatCount', 'indefinite');
animate.setAttribute('dur', '6s');
animate.setAttribute('begin', rnd+'s');
animate.setAttribute('fill', 'freeze');
stop.appendChild(animate);
svgDefs.appendChild(radialG);
}
createNewElement();
Here is a link to see what's happening.
http://jsfiddle.net/cpUbS/2/
Any idea of what I'm missing?
thanks!

SVG documents have a timeline which by default starts at 0 seconds when the first thing to animate is created and then increments.
You are creating all of your elements with a begin of 6s so when the document timeline reaches 6 seconds they all start animating in sync.
Increment the begin of each element so that they start at the point of the timeline you want them to.

Related

How to extract pixel value from geometry points in shp format (2500 points) starting from an Image Collection resempled

I'm trying to extract the value of each single band of Sentinel-2 after resampling the bands from 10 meters to 30 meters using the resolution of the Landsat-8 (I didn't know how to do this in another way)
This is the code using band 4 as an example. When I try to export the values ​​in a table the running time is infinite and I was not able to extract even the value for a single point.
N.B. my area is very large, it corresponds to all of southern europe
thank you !
function maskS2clouds(image) {
var qa = image.select('QA60');
var cloudBitMask = 1 << 10;
var cirrusBitMask = 1 << 11;
var mask = qa.bitwiseAnd(cloudBitMask).eq(0).and(qa.bitwiseAnd(cirrusBitMask).eq(0));
return image.updateMask(mask).divide(10000).select("B.*").copyProperties(image, ["system:time_start"]);
}
var start = '2012-01-01';
var end = '2022-12-31';
var cld_max = 30;
var s2 = ee.ImageCollection("COPERNICUS/S2_SR_HARMONIZED")
.filterBounds(Eur)
.filterDate(start,end)
.filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE',60))
.map(maskS2clouds);
var land8 = ee.ImageCollection('LANDSAT/LC08/C01/T1_SR').filterBounds(Eur)
var b4 = land8.select('B4').filterBounds(Eur); // 30-m resolution
var b4s = s2.select('B4').filterBounds(Eur); // 10-m resolution
var proj_10m = b4.first()
.projection();
function resample(image) {
var b4s = image.select('B4');
var b4s_res = b4s.resample('bilinear').reproject(proj_10m);
return b4s_res;
}
var b4s_res =b4s.map(resample).filterBounds(Eur);
//original code
var pts = b4s_res.map(function(img) {
var obs = img.reduceRegion(
{geometry: points , reducer: ee.Reducer.median(), scale: 80});
return img.set('B4', obs.get('B4'));
});
Export.table.toDrive({
collection: pts,
description: 'table_csv',
folder: 'earth_engine_demos',
fileFormat: 'CSV'
});
//test with geometry composed of two single points
var pts2 = b4s_res.map(function(img) {
var obs2 = img.reduceRegion(
{geometry: geometry , reducer: ee.Reducer.median(), scale: 80});
return img.set('B4', obs2.get('B4'));
});
Export.table.toDrive({
collection: pts2,
description:'prova_csv',
folder: 'earth_engine_demos',
fileFormat: 'CSV'
});
Is it possible to find a faster way to extract the value of the points (2500 random points) in the table? Do you also know another way to apply a resampling on all bands simultaneously and extract the corresponding value of each point for each single band?

How can an AnimationAction stop at the last frame without looping in three.js?

I'd like to stop an AnimationAction at the last frame that I've created with morph targets.
https://threejs.org/docs/#api/en/animation/AnimationAction
I've tried animationAction.clampWhenFinished = true; but that doesn't seem to work.
I've looked at older stackoverflow questions and searched through forums but the solutions didn't work.
var cubeTarget1 = new THREE.BoxGeometry(20, 10, 10);
var cubeTarget2 = new THREE.BoxGeometry(20, 10, 50);
var cubeTarget3 = new THREE.BoxGeometry(60, 10, 10);
cubeGeometry.morphTargets[0] = {name: 't1', vertices: cubeTarget1.vertices};
cubeGeometry.morphTargets[1] = {name: 't2', vertices: cubeTarget2.vertices};
cubeGeometry.morphTargets[2] = {name: 't3', vertices: cubeTarget3.vertices};
Is there a way I can do something like: (this doesn't work, it loops back to the first morphTarget)
var clip1 = THREE.AnimationClip.CreateFromMorphTargetSequence('run', [cubeGeometry.morphTargets[0],cubeGeometry.morphTargets[1]], 30);
var action1 = mixer.clipAction(clip1);
action1.play(); // starts at cubeTarget1 ends at cubeTarget2 (animating between them, without a loop)
// and at a later point I'd like to do
var clip2 = THREE.AnimationClip.CreateFromMorphTargetSequence('run', [cubeGeometry.morphTargets[1],cubeGeometry.morphTargets[2]], 30);
var action2 = mixer.clipAction(clip2);
action2.play(); // starts at cubeTarget2 ends at cubeTarget3 (animating between them, without a loop)
Here's my fiddle:
https://jsfiddle.net/foreyez/uy8abk6v/
This is my approach that I used with an enemy bot gltf model on my three.js prototype first person shooter. The robot has a single track animation with many frames. I had to split the frames up into sub clips with the following code then applied clampwhenfinished.
var EnemyHeavyBotFallBackClip = THREE.AnimationUtils.subclip(gltf.animations[0], “Take_001”, 1300, 1355);
actionEnemyHeavyBotFallBackMixer = mixer.clipAction(EnemyHeavyBotFallBackClip);
actionEnemyHeavyBotFallBackMixer.clampWhenFinished = true;
actionEnemyHeavyBotFallBackMixer.setLoop(THREE.LoopOnce);
actionEnemyHeavyBotFallBackMixer.play();
https://www.shanebrumback.com/super-soldier-battle-intro.html
Disclaimer: This is my website.
I looked at the three.js code. And inside LoopOnce the section involving clampWhenFinished doesn't get hit at all.
For now I'll do it in a very crude way until I find a better solution:
action.setDuration(5).play();
setTimeout(function()
{
action.paused = true;
},2500); // half of the duration
Another way I've been doing is to use morphTargetInfluences and just increment it on an animation loop:
function animate() {
if (cube.morphTargetInfluences[0] < 1)
cube.morphTargetInfluences[0] += 0.01;
controls.update();
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
Use Tween.js if you need more functionality.
It took me a while to get this working, a lot of the online examples seem to be outdated and/or non-working. Try:
var clips = THREE.AnimationClip.CreateClipsFromMorphTargetSequences(geometry.morphAttributes.position, 60, true);
mixer = new THREE.AnimationMixer(points);
var action = mixer.clipAction(clips[0]).setDuration(10);
action.clampWhenFinished = true;
action.setLoop(THREE.LoopOnce);
action.play();
Note the "noLoop" parameter of CreateClipsFromMorphTargetSequences(name: String, morphTargetSequence: Array, fps: Number, noLoop: Boolean) needs to be "true" along with clampWhenFinished = true and setLoop(THREE.LoopOnce).
Full example here https://jsfiddle.net/jm4ersoq/

How do I "register" a dragged group to specific coordinates with d3?

I'm trying to do something that (it seems to me!) should be simple,
but my attempts are getting very convoluted, and I'm looking for d3
guidance.
Suppose I have a dragged group object (consisting of a rectangle and
its text) that has been dropped someplace at the end of a drag. I want
to "register" this group at specific coordinates. How do I do that?
I am adding my code to the dragended() function associated with
d3.drag's on("end") event.
function dragended(d) {
var move = d3.select(this);
var g = move._groups[0][0]; // same as this!
var rect = g.children[0]
rect.x = schedLeft;
rect.y = schedTop;
d3.select(this).classed("active", false);
}
I bind d3.select(this) to the variable move, and get an object
like that shown in the attached figure (Chrome developer Local).
EDIT: move._groups[0][0] is silly; it's the same as this!
Using this I can get the group (with child rect and
text nodes) that I want to move.
schedLeft is the x coordinate where I want the group dropped. The rect node has x and y attributes, but my rect.x = schedLeft
doesn't change anything (watching in the debugger).
Is that even the right way to have a transition of the entire group
(ie, including the attending text) to its new location?
Thanks to hints I found on SO here (from 2013!) I got it working using this:
function dragended(d) {
// register dragged move into hourSched
var top = schedTop + (nsched++) * menuWOHgt;
var transX = newDropX - d.x ;
var transY = newDropY - d.y;
var tstr = `translate( ${transX}, ${transY} )`;
d3.select(this).attr("transform", tstr)
.classed("active", false);
}

Three JS : Attaching an object to another

I'm trying to attach a cube to another cube at a specific point. I'm able to get collision and .add() is working fine. However, I want to add child cube exactly at point where collision occurs to the parent cube.
for (var vertexIndex = 0; vertexIndex < MovingCube.geometry.vertices.length; vertexIndex++) {
var localVertex = MovingCube.geometry.vertices[vertexIndex].clone();
var globalVertex = localVertex.applyMatrix4( MovingCube.matrix );
var directionVector = globalVertex.sub( MovingCube.position );
var ray = new THREE.Raycaster( originPoint, directionVector.clone().normalize() );
var collisionResults = ray.intersectObjects( collidableMeshList );
if ( collisionResults.length > 0 && collisionResults[0].distance < directionVector.length() )
console.log(" Hit and collision detected " + SELECTED);
MovingCubeBig.add(SELECTED);
// Is there way to get collision point and attach object at that point?
}
Intersections results should include a point attribute.
https://github.com/mrdoob/three.js/blob/master/src/core/Raycaster.js#L255
Maybe you can use this to attach the child at the right position ?
Also, this example may help http://threejs.org/examples/#webgl_geometry_terrain_raycast

CKEditor: set cursor/caret positon

How can I position the caret in CKEditor3.x?
I have 2 positions and I want use insertHTML() on both positions.
Pseudo-code:
editor.setCaret(20); // function does not exists
editor.insertHtml('::');
editor.setCaret(40); // function does not exists
editor.insertHtml('::');
I have tried (to set caret to position: 20):
var ranges = [];
var range = new CKEDITOR.dom.range( this.document );
range.startOffset = 20;
range.endOffset = 20;
ranges.push( range );
editor.getSelection().selectRanges( ranges );
This is not working. Can anybody help me please?
To insert text or do something with html in the editor you don't need to get the caret position.
Treat it as usual html.
P.S. If you probably want to restore cursor position after dom manipulating, try this
var s = editor.getSelection();
var selected_ranges = s.getRanges(); // save selected range
// do something
s.selectRanges(selected_ranges); // restore it
If you use insertElement instead of insert html (and say, insert a span element) the following should probably work:
editor.insertElement(element);
var range = new CKEDITOR.dom.range(editor.document);
range.moveToElementEditablePosition(element, true);
editor.getSelection().selectRanges([range]);

Resources