I'm new to Raphael and coding in general, so please bear with me as I lumber through this question. I am having trouble animating groups of paths in Raphael. My desired effect is a set of paths running individual animations while moving around the paper in unison. Here is an example:
path1 = paper.path("path string").attr({fill: "#fff", stroke: "#000"});
path2 = paper.path("path string").attr({fill: "#fff", stroke: "#000"});
path3 = paper.path("path string").attr({fill: "#fff", stroke: "#000"});
pathSet = paper.set(path1, path2, path3);
pathSet.animate({transform: "t500,500"}, 1000);
path1.mouseover(function(){path1.animate({transform: "s1.6,r10"}, 1000)});
path2.mouseover(function(){path2.animate({transform: "s1.6,r10"}, 1000)});
path3.mouseover(function(){path3.animate({transform: "s1.6,r10"}, 1000)});
In the above example, the pathSet will animate just like it should, but when I mouse over the individual paths, they don't just scale and rotate in place, but translate back to their original coordinates (where they were prior to the pathSet animation). I read in the docs about the relative "t,r,s" and absolute "T,R,S" parameters for transformations and thought that was it, but they don't seem to make a difference. Any help is much appreciated!
You've hit upon what I take to be one of Raphael's biggest weaknesses: transform animations are difficult to combine gracefully!
This won't be a perfect solution, but you can always use the mouseover/mouseout handlers to append/counter the changes you want. For instance:
path1.mouseover(function(){path1.animate({transform: "...s1.5,r10"}, 1000)});
path2.mouseover(function(){path2.animate({transform: "...s1.5,r10"}, 1000)});
path3.mouseover(function(){path3.animate({transform: "...s1.5,r10"}, 1000)});
path1.mouseout(function(){path1.animate({transform: "...s0.66,r-10"}, 1000)});
path2.mouseout(function(){path2.animate({transform: "...s0.66,r-10"}, 1000)});
path3.mouseout(function(){path3.animate({transform: "...s0.66,r-10"}, 1000)});
The append/counter approach will work fine so long as you don't need a stateful reaction from any given element. Once that happens, it seems to me to make more sense to create a wrapper class for a type of object that will keep track of where it should be, adjusting the absolute transform as necessary. But you may not need such a thing.
Related
Just trying to up the stroke width a little on the country polygons for three-globe.
There doesn't appear to be a helper function for this material or any settings beyond color.
I had the bright idea of looping through all the children of the globe object, very crude but:
for (let i in Globe.children[0].children[4].children){
const child = Globe.children[0].children[4].children[i];
child.children[1].material.linewidth = 3;
child.children[1].material.color = new THREE.Color('rgba(255,255,255,1)');
}
This appears to have no effect on the line width. It does, however, successfully change the color, so I think I'm close, though I really hope there's a better way than this.
I'm sorry to inform you that the .linewidth property is very poorly supported due to OpenGL limitations. You can see an explanation in the LineBasicMaterial.linewidth documentation
Due to limitations of the OpenGL Core Profile with the WebGL renderer on most platforms linewidth will always be 1 regardless of the set value.
You'll run into this issue if you're using THREE.Line or THREE.LineSegments. However, there is an alternative you could use with THREE.Line2, which circumvents the limitation by drawing lots of instanced gl.TRIANGLES instead of gl.LINE. You can see it in action in this example. In fact, there are 3 demos of fat lines, each one with a slightly different implementation. You would then have to substitute the outlines of the country with your own fat lines.
I have recently come across beautiful icon animations in Apple's Home app. This is example of opening/closing garage doors: https://giphy.com/gifs/0it1uTDtVR1Uw1FByx
I wonder how to make these animations. There are ways I can think of:
Manually creating shapes and animating them in code (this would be so hard to do)
Using some animation tool and exporting *.gif frames (but in this way we will lose vector graphics)
Using some animation tool and exporting *.svg frames (is this efficient?)
Using some animation tool that will generate code (for example JS/CSS) with all the shapes and animation (Does such tool/program exist?)
Does anyone have experience with creating this type of animations? It would be great if you could share this experience :)
Obviously no answer will be exhaustive. Pure "CSS3 art" is route that I've seen people use because it can define complex geometry and animations precisely. But here are some ways I've looked into using SVGs.
You can actually embed a script tag in an SVG that animates the elements. Something like this:
<svg>
<!-- svg objects -->
<script><![CDATA[!
//... Javascript to animate svg objects...
]]></script>
</svg>
You can also use a library like snapsvg.io where the construction of an animated svg is done purely with JavaScript. Here's the example they use for their quickstart page:
var s = Snap("#svg");
var bigCircle = s.circle(150, 150, 100);
bigCircle.attr({
fill: "#bada55",
stroke: "#000",
strokeWidth: 5
});
var smallCircle = s.circle(100, 150, 70);
var discs = s.group(smallCircle, s.circle(200, 150, 70));
discs.attr({
fill: "#fff"
});
bigCircle.attr({
mask: discs
});
smallCircle.animate({r: 50}, 1000);
Otherwise you can use a codeless animated-svg creator like this one.
Disclaimer: I haven't tested the codeless site past the demo plan and probably will never use it. My personal preference would probably be the first suggestion but a JavaScript library like snapsvg.io seems like a nice middle ground.
I would go with option 4. Using some animation tool that will generate code (for example JS/CSS) with all the shapes and animation
I think it can be done with a tool called lottie, which uses json file exported by AfterEffects plugin called bodymovin.
Lottie web docs
I'm backend developer for several years but a newbie in frontend issues.
I used "graphviz" (using d3.js) to draw an SVG graph from DOT notation.
Everything is working fine but one thing I don't get in my mind:
If I "open" another (or the same one) graph its starting position is the
same as this from the previous drawn graph even if I completely remove
the whole node content from the dom as follows:
var svg = d3.selectAll("svg");
var otherBelow = svg.selectAll("*");
otherBelow.remove();
// svg.remove();
Doing this and checking the page source the nodes below SVG are realy dropped
but drawing the new graph it has exactly the position of the previously
moved graph in "transform" attribute. Doing a work around by resetting the
position bevore solves this problem but then the problem remains for the
"moving on mousedown" capability. Then the graph immediately "jumps" to the old
ones position. But therefor I can't even get an information about somewhere
in the page source. Really the generated page code is 100% the same (with
diff tool) but has a different behaviour. Don't understand how this is possible.
So now my question: Is there a kind of caching? Or is there perhaps the
browser cache used somehow internally? How to fix this?
P.s. if I remove the SVG node itself I get a completely courious behaviour.
Then the newly drawn graph is not movable at all.
This (ugly) workaround does it for me.
// Snipped to render a new graph and reset its position
// #graph -> id of d3-graphviz div-container
document.getElementById('graph').innerHTML = ''
setTimeout(() => {
d3.select("#graph").graphviz()
.dot(yourDotData)
.render()
}, 50)
Explanation/Assumption why this works:
It seems that the deletion of the old graph with .innerHTML = ''and the creation of the new one should not happen in the same rendering phase/at the same time, therefore the timeout function.
The second part of the workaround is to use a new graphivz-instance to render the new graph, therefore the
d3.select(...) within the timeout function.
The graphviz renderer is still present on the element it was created on and has all its data still intact.
Removing the svg and then reuse the renderer is not a valid use case. Nico's answer is probably correct, but there are better ways to do it, but in order to tell you how you should do it instead I would need so see all of your code so I can understand what you really want to do.
I've been looking around for how to create animations in Om, I've tried creating a RaphaelJs component with moderate success. I get the animation I want, but for some reason Om renders multiple instances of the SVG element.
Looking at the animation example in the Om github folder uses setInterval to change the values you want to animate, which is less than ideal.
I'm aware of the CSSTransitionGroup addon, but it looks like you can only flip between preset animations defined in the CSS, you can't decide to do something like rendering a path and having a shape following it with randomised timings. Please feel free to correct me if you can dynamically define animations using it.
Does anyone have any good examples of performing simple animations? Just translating or rotating simple shapes would give me an idea of how to start tackling it from there.
You can use CSSTransitionGroup to animate position/movement, orientation and other visual properties like opacity, color, borders or shadows (perhaps using keyframes) or more complex hacks. The major limitation of this approach is that it only allows you to animate mounting and unmounting of components and then only through animation defined in CSS.
If you need to animate components during their mounted lifetime or you want more fine-grained control over what you can animate, you might want to take another approach like what I do in this code.
This is how you would use CSSTransitionGroup from Om.
For this to work, you need to use the with-addons version of React (eg react-with-addons-0.12.1.js or react-with-addons-0.12.1.min.js).
(def css-trans-group (-> js/React (aget "addons") (aget "CSSTransitionGroup")))
(defn transition-group
[opts component]
(let [[group-name enter? leave?] (if (map? opts)
[(:name opts) (:enter opts) (:leave opts)]
[opts true true])]
(apply
css-trans-group
#js {:transitionName group-name
:transitionEnter enter?
:transitionLeave leave?}
component)))
Then to use it, you can do:
(transition-group "example" (when visible? (om/build my-component data)))
Now toggle visible? to animate my-component being mounted and unmounted. If you want to disable either the enter or leave animation:
(transition-group
{:name "example"
:enter false} ; Only animate when component gets unmounted, not when mounted
(when visible? (om/build my-component data)))
You can also animate adding or removing from/to lists of items:
(transition-group "example" (om/build-all my-component list-of-data))
Or using map, perhaps something like:
(transition-group "example" (map #(dom/li %) list-of-data))
You also need to add the correct CSS:
.example-enter {
opacity: 0.01;
transition: opacity .5s ease-in;
}
.example-enter.example-enter-active {
opacity: 1;
}
.example-leave {
opacity: 1;
transition: opacity .5s ease-in;
}
.example-leave.example-leave-active {
opacity: 0.01;
}
Note that unless you disable one of the animations, you need to include both in the CSS. For example, if you leave out the leave animation, then your component may not get unmounted as React will hang waiting for the animation to complete. Simple fix is to disable it using {:leave false} or to include the leave animation in your CSS.
One other gotcha to be aware of: this will only animate child components if the transition group is mounted before the children. If the children and the transition group are mounted at the same time, then they won't be animated. This can be a bit awkward sometimes. For example, the above code snippets would not animate without the (when visible? ...) as without toggling, the child would be mounted at the same time as the transition group. Also, the build-all example below works best if list-of-data is not prepopulated but instead populated after mounting. For this reason, CSSTransitionGroups work best for code that switches between views/components or lists of data that gets modified by the user, but doesn't work for animating initial display of components on page load.
Perhaps something like:
(transition-group "view-selection"
(condp = current-view
"home" (om/build home-page data)
"blog" (om/build blog-page data)
"about" (om/build about-page data)
:else (om/build error-404-page data)))
-
Finally, if you do not wish to use a helper function, you can use css-trans-group directly:
(css-trans-group
#js {:transitionName "example"}
(when visible? (om/build my-component data)))))
Or, if using a lists of child components (eg through map or build-all):
(apply
css-trans-group
#js {:transitionName "example"}
(om/build-all my-component list-of-data))))
I have not yet used the low-level TransitionGroup API. More information can be found on the React CSSTransitionGroup page.
Care to look into a ClojureScript port of https://github.com/chenglou/react-tween-state or https://github.com/chenglou/react-state-stream?
TransitionGroup provides nothing but helpers for hooking onto some lifecycle events. It theoretically has nothing to do with animation. If you want an actual animation API, give a look at the two things I made above. The readmes should provide enough information for the rest.
I'm building a strategy game in the browser since 2 years back. Its already actively played by a small crowed of people so it is a working game.
Our problem is that its resource hungry. Basically you want opera or chrome. IE9 is more or less unplayable and firefox can be quite slow on some maps.
The game is a tile based top down game using 64x64pixel DIVs for the map.
We are currently in the end phase and we are focusing on optimizations. One of the things that eat resources is our animated water. We have 32 different tiles of water split into 15 frames each. So 480 64x64 images in one .gif file that is 1.1 mb.
Here is a link to the water: http://www.warbarons.com/beta5/terrain/water/water2.gif
Our game uses Fog of War to hide enemy units and castles that you cant see just like any RTS game. So on top of the .gif there is usually a layer with a transparent PNG.
It seems like this solution is quite demanding on the browser. When I scroll the map to show water in FireFox CPU goes up to 25% while its around 4-5% when no water is in sight.
I've been googling for a few days now trying to get an idea of a better technique. I've found two other way of doing this, either with a canvas tag which is iterating over a spreadsheet or using CSS to loop over a spreadsheet.
The problem I see with those two options is that all water tiles must remain in sync. If one starts playing before another one the waves wont be in sync which will break the seamless look.
I wonder if anyone have an idea to solve this? I know that having multiple gif animations will result in the out of sync problem.
Is there some cleaver way to use canvas to do this? Is it even possible to mix canvas with divs or would that require that we change the whole map engine?
Any help would be greatly appreciated.
Bit of a novice work around and a longshot, but:
For preparation, make a sprite-sheet of all of the different types of water tiles, with the first frame on the left, with a new row for each type, descending down.
Create a <div> with an 'overflow' attribute of 'hidden' behind the canvas
Make the background of the canvas transparent
Inside of the div, you can use <div>s for the water tiles and adjust their 'margin' attributes to match the position of the map
Give them all a class designation 'water', as well as a class to match the type of water tile (like 'dockleft', 'beachtop', etc.)
In your <style> element, make a class rule '.water'
Give the rule the 'background-image' attribute, linking to whatever and wherever your sprite-sheet is
For each type of water tile, create a class rule that corresponds to each tile-type and give them a matching y position for the sprite-sheet
Create a new <style> element with an id, one that will contain the background-position of all of the frames
Create a javascript variable to conatin the x position of all of the backgrounds
Inside your game loop, decrement the variable by 64 for whenever you want the sprite to change (until it equals 960, then set it 0)
When the variable changes, set the contents of the new <style> element to the new CSS rule for its 'background-position-x' using the variable
Meh. A little much, I know, but better than looping through an array and gobbling up system resources, changing each element individually (at least I assume so). Here's a simplified code sample:
<script type="text/javascript">
var pos = 0; // background-position-x variable
function loop() {
document.getElementById('changeMe').innerHTML = ".water{background-position-x:" + pos + "px;}"; //changes the contents of the <style> with the id 'changeMe'
//changes the <style> with id 'Change'
pos -= (pos == 960) ? -960 : 64; //assuming your sprite-sheet is oriented horizontally
setTimeout('loop();', 100);
}
</script>
<style type="text/css">
/* Remains unchanged */
.water {
width: 64px;
height: 64px;
background-image: url('spriteSheet.png');
}
.dockleft{
background-position-y: 420px;
/* If all of your sprites are on one sheet, you can set the
'background-position-y' attribute for each type of water tile and
give the 'water' class one sprite-sheet url for all of the types */
}
</style>
<style id="changeMe" type="text/css">
/* Changed by 'loop()' */
</style>
<body onload="loop();">
<div class="water dockleft"></div>
</body>