Is it possible to animate the second value of the stdDeviation attribute?
Actually Gsap allows to animate numerical attribute like stdDeviation :
.to(blurNode, 0.5, {attr:{stdDeviation:20}, "blur")
But in the case of the stdDeviation we can have 2 values like so :
<feGaussianBlur in="SourceGraphic" stdDeviation="0 0" />
Is it possible to animate only the second value?
Sure, it should be as simple as:
TweenMax.to("#test", 5, {attr:{stdDeviation:"0 20"}});
Here's a demo:
http://codepen.io/anon/pen/KgrZKK?editors=1010#
(Just make sure you've got a relatively recent version of GSAP)
Related
I am confused with gsap's Flip.fit moving to coordinates.
I have a game board with 182 tiles and 182 playing tiles.
The goal
When the user clicks the bag, a random playing tile is selected and is "supposed" to move over the tile on the board.
If you change
Flip.fit(PTILE[tileArray], TILE[tileArray], {duration: 1 , scale: true});
when changing { duration: 0, ... } the move works as expected, however no animation. When duration is above zero, the final location is very random.
codepen
I'm not sure how the duration affects the final position, however, I found a way to get the positions right. That is reset the transform of your PTILE before telling GSAP to do the Flip animation.
// reset transform value
gsap.set(PTILE[tileArray], { transform: "" });
// animate with new transform value
Flip.fit(PTILE[tileArray], TILE[tileArray], {
duration: 1,
scale: true
});
My reason is that PTITLE and TITLE are placed in different <g> tags which means their transform systems are inconsistent. Plus, Flip.fit() will act like gsap.to() with new TITLE position is the to object, GSAP will try to calculate the from object from your original transforms which are already set in the SVG as transform:matrix(). This process, somehow, is messing up. So what I did is give GSAP an exact transform value for the from object, which is empty.
Ok, I found out that Inkscape stores the SVG with inline transforms that threw the animation off. I tried saving in plain or optimised, but still had no luck.
So there are two solutions.
Use SVGOMG an online SVG cleaner.
Use Affinity Designer application which can export and flatten transforms.
The key to rule out other factors is to use relative coordinates and flatten transforms.
I have included a screenshot of Affinity exporting options.
Affinity Export screenshot
I want to create a (semi) transparent box
<mesh position={position} transparent opacity={0.1}>
<boxGeometry args={scale}>
<meshPhingMaterial color={(0.5, 0.5, 0.5)} opacity={0.1} transparent />
</boxGeometry>
</mesh>
I tried several values for opacity, but the box stays non transparent.
What's wrong?
<mesh position={position} scale={scale}>
<boxGeometry />
<meshPhongMaterial color="#ff0000" opacity={0.1} transparent />
</mesh>
you can consult threejs docs for all of these objects: https://threejs.org/docs/index.html#manual/en/introduction/Creating-a-scene all the props and constructor args are listed in there.
and at least once skip through this section real quick https://docs.pmnd.rs/react-three-fiber/API/objects to learn about react semantics.
ps. (0.5, 0.5, 0.5) in javascript just means that it will return the last number. const a = (1, 2, 3) yields 3.
pps. it is better to scale the mesh instead of constructor args. if you change args the object must get re-created because you literally do new BoxGeometry(scale). on the mesh on the other hand it won't have to do it and it's faster.
I have a chart with proper display of data, but my Y-Axis is linear (should be) and it crops data (see screenshot).
I expect Y-Axis to show linear data AND respect the edge (max) value of the chart.
I was trying to work with d3-scale but I failed - don't know how to "append" max value to the scale. The only way I figured is to manually calculate all the ticks which I'd like to avoid.
My Y-Axis code is
<YAxis
domain={[data.yAxis.min, data.yAxis.max]}
scale="linear"
tickFormatter={formatEnergyAxis}
/>
Where min is 0 and max is 3200 (unit conversion happens in formatters).
Is there a way to adjust the scale?
If possible, call the function .nice() inside YAxis. Otherwise, call it before passing the values to the binding:
d3.scaleLinear().domain([0, 3200]).nice().domain()
// [0, 3500]
That would be
<YAxis
domain={d3.domain([data.yAxis.min, data.yAxis.max]).nice().domain()}
scale="linear"
tickFormatter={formatEnergyAxis}
/>
On your Y-Axis, you can specify your last tick to be visible with the props interval set to preserveEnd, like this:
<YAxis
domain={[data.yAxis.min, data.yAxis.max]}
scale="linear"
tickFormatter={formatEnergyAxis}
interval="preserveEnd"
/>
You can also use the value preserveStartEnd to be have the root & edge values visible.
I can't grok the docs on d3's ordinal scales. The way I read it (and the way it works for linear scales, I feel I should be able to proceed like this:
color = d3.scale.ordinal();
color.domain([0, 100]); // Input is any percentage point 0-100
color.range([ // Output is a scale of colors from "bad" to "good"
'red','orange','blue','green'
]);
This doesn't give me the results I expect:
color(0); // "red". Ok, that makes sense
color(1); // "blue". Huh? This should be "red"
color(100); // "orange". Really? I'm confused. What's the range?
color.range(); //["red", "orange", "blue", "green"]. That looks right...
color.domain(); // [0,1,100]. Um...
It looks like it's treating inputs as discrete categorical values when I want to treat them like numbers.
The correct approach for mapping a range of numbers to discrete outputs is to use quantize. The difference wasn't clear to me and ordinal seemed intuitive. Figured it out now.
A working solution looks like this:
color = d3.scale.quantize();
color.domain([0, 100]);
color.range([
'red','orange','blue','green'
]);
color(0); // "red"
color(1); // "red"
color(99); // "green"
These links here helpful in figuring this out:
http://roadtolarissa.com/blog/2015/01/04/coloring-maps-with-d3/
What is the difference between d3.scale.quantize() and d3.scale.quantile()?
The approach to this is not exactly how it works. The domain you listed will point to 2 specific values in the range, the 2 first values - red and orange. Any other value that you add to the domain via color(n); will extend the domain array, eg. 1 is considered the 3rd index, therefore it is assigned the 3rd item in the range, if you were to call another item with color(n) you would get the 4th index. That is how the range method works.
I am trying to animate the changing of the viewport of an SVG element. When a particular ellipse in the SVG is clicked the viewport is changed so that it is zoomed in on the ellipse. From my interpretation of the W3C animate specification, when fill="freeze" is used, the value in the to attribute will stay. However, when I use console.log("after animation: "+canvas.getAttribute("viewBox")); the viewBox is the same as before (the animation does zoom in). For extra info, the <animate> is added when the ellipse is clicked. This is the code for how the animation is added to the <svg>;
var canvassnap=Snap(canvas);
var animation = '<animate id="smoothpan" attributeName="viewBox" begin="0s" dur="'+duration+'ms" from="0 0 1280 720" to="'+minX+' '+minY+' '+(maxX-minX)+' '+(maxY-minY)+'" fill="freeze" />';
var parse = Snap.parse(animation);
canvassnap.add(parse);
Do I not understand the specification properly?
SVG has two values for each attribute, the base value which you can get either with getAttribute or via element.viewBox.baseVal and the animated value which you can get via element.viewBox.animVal.
If an element is not the subject of SMIL animation then animVal == baseVal.
SMIL animation only affects the animVal and it's the animVal that is used for rendering.