Snap SVG Animation Performance - performance
The Problem:
I'm using Snap SVG to draw and subsequently animate 4 graphics (desktop, laptop, tablet, phone), so that they morph into one another every 5 seconds. The devices are built using basic lines and shapes, as well as a PNG screenshot for each device. You can see it in action here. My original code is as follows:
var makeDesktop = function() {
deviceOuter.animate({width: 420, height: 300, rx: 20, ry: 20, transform: 'T0,0'}, 1000, mina.easeinout);
screenOuter.animate({width: 380, height: 220, transform: 'T0,0'}, 1000, mina.easeinout);
screenImageDesktop.animate({width: 380, height: 220, transform: 'T0,0', opacity: 1}, 1000, mina.easeinout);
screenImageLaptop.animate({width: 380, height: 220, transform: 'T0,0', opacity: 0}, 1000, mina.easeinout);
screenImageTablet.animate({width: 380, height: 220, transform: 'T0,0', opacity: 0}, 1000, mina.easeinout);
screenImagePhone.animate({width: 380, height: 220, transform: 'T0,0', opacity: 0}, 1000, mina.easeinout);
camera.animate({r: 2.5, transform: 'T0,0'}, 1000, mina.easeinout);
desktopDivider.animate({d: "M0,260, 420,260", opacity: 1}, 1000, mina.easeinout);
laptopMidDivider.animate({d: "M20,300, 400,300", opacity: 0}, 1000, mina.easeinout);
laptopMidLeft.animate({d: "M20,300, 20,300", opacity: 0}, 1000, mina.easeinout);
laptopMidRight.animate({d: "M400,300, 400,300", opacity: 0}, 1000, mina.easeinout);
deviceBaseLeft.animate({d: "M165,300 Q160,340 140,340", opacity: 1}, 1000, mina.easeinout);
deviceBaseRight.animate({d: "M255,300 Q260,340 280,340", opacity: 1}, 1000, mina.easeinout);
deviceBaseBottom.animate({d: "M140,340, 280,340", opacity: 1}, 1000, mina.easeinout);
mobileButton.animate({r: 10, transform: 'T0,0', opacity: 0}, 1000, mina.easeinout);
$("#btn-desktop").addClass("active");
devicePosition = 0;
};
I've also tried reformatting to make use of a set:
var makeDesktop = function() {
var set = Snap([deviceOuter, screenOuter, screenImageDesktop, screenImageLaptop, screenImageTablet, screenImagePhone, camera, desktopDivider, laptopMidDivider, laptopMidLeft, laptopMidRight, deviceBaseLeft, deviceBaseRight, deviceBaseBottom, mobileButton]);
set.animate([{width: 420, height: 300, rx: 20, ry: 20, transform: 'T0,0'}, 1000, mina.easeinout], [{width: 380, height: 220, transform: 'T0,0'}, 1000, mina.easeinout], [{width: 380, height: 220, transform: 'T0,0', opacity: 1}, 1000, mina.easeinout], [{width: 380, height: 220, transform: 'T0,0', opacity: 0}, 1000, mina.easeinout], [{width: 380, height: 220, transform: 'T0,0', opacity: 0}, 1000, mina.easeinout], [{width: 380, height: 220, transform: 'T0,0', opacity: 0}, 1000, mina.easeinout], [{r: 2.5, transform: 'T0,0'}, 1000, mina.easeinout], [{d: "M0,260, 420,260", opacity: 1}, 1000, mina.easeinout], [{d: "M20,300, 400,300", opacity: 0}, 1000, mina.easeinout], [{d: "M20,300, 20,300", opacity: 0}, 1000, mina.easeinout], [{d: "M400,300, 400,300", opacity: 0}, 1000, mina.easeinout], [{d: "M165,300 Q160,340 140,340", opacity: 1}, 1000, mina.easeinout], [{d: "M255,300 Q260,340 280,340", opacity: 1}, 1000, mina.easeinout], [{d: "M140,340, 280,340", opacity: 1}, 1000, mina.easeinout], [{r: 10, transform: 'T0,0', opacity: 0}, 1000, mina.easeinout])
$("#btn-desktop").addClass("active");
devicePosition = 0;
};
My Question
Seeing as every animation's duration is 1000ms and has the same easing curve, is there a less expensive way of achieving the same effect? Is there any performance benefit from using a set in this instance, as it drastically reduces readability.
Its hard to guess without seeing a jsfiddle to play around with different options and separate it from the rest of the webpage. I'd first play around with it separately.
The advantage 'should' be, that you are only running one timer, instead of a timer for every element, which certainly can create an overhead.
With a lot of elements, this would have an effect, I think in your case, its borderline. It may perform a little better, but I'm not sure it would be noticeable. Only you can tell that. One thing I would say, is test them both on mobile, as that is often a lowest performing case for svg animation.
Other things that may be worth looking into...
Are there multiple transforms applied to an element (eg a transformed element inside a group or another container thats transformed), as that will slow things down.
CSS transforms/animations can often perform better, but you will want to check support for browsers/devices. Velocity.js could be worth looking at.
Does having a viewBox affect performance, could it be quicker if everything was initially the right size, what about the images ?
Regarding readability, everything doesn't have to be kept onto 2 lines in the alternative version, you can still make things readable I would think (if not more readable). Eg could it be rewritten like..
var deviceOuterChanges = [{width: 420, height: 300, rx: 20, ry: 20, transform: 'T0,0'}, 1000, mina.easeinout];
var screenOuterChanges = [{width: 380, height: 220, transform: 'T0,0'}, 1000, mina.easeinout];
....
var set = Snap([deviceOuter, screenOuter.... mobileButton])
.animate([ deviceOuterChanges,
screenOuterChanges,
...
]);
You could also reuse some of them, as all of the screenImage objects have the same animation attributes.
Related
How to set the backgroundcolor of BottomTabNavigator to transparent? without using position: 'absolute'
I'm trying to make the background of my BottomTabNavigator transparent. I've tried setting the position to 'absolute', this makes the background transparent but now the tab bar is not clickable anymore. Does anyone knows a solution? tabBarOptions: { inactiveBackgroundColor : COLORS.TINTCOLOR, activeBackgroundColor: COLORS.TINTCOLOR, activeTintColor: COLORS.WHITE, inactiveTintColor: COLORS.WHITE, showLabel: false, labelStyle: { fontSize: 12 }, style: { borderTopWidth: 0, borderTopColor: COLORS.TINTCOLOR, height: 50, position: 'absolute', left: 0, right: 0, bottom: 0, backgroundColor: 'transparent', borderTopLeftRadius: 25, borderTopRightRadius: 25, overflow: 'hidden', }, },
How to create list of vars in loop?
I have a main colour #abc and we can create colour with darken with percentage how can i create list of darken colours with a loop? #mixin create-color($main) { create some vars } #include create-color(blue); i will get $c-green-1: green $c-green-2: (green-lighten 10%) $c-green-3: (green-lighten 20%)
This will accomplish what you're after: #mixin alphaColor($name,$color) { #for $i from 1 through 10 { .c-#{$name}-#{$i} { color: rgba($color,$i/10); } } } #include alphaColor("blue",blue); #include alphaColor("red",#ed1414); #include alphaColor("absurd",rgb(20,237,20)); This is a mixin that will take a color (named, hex, rgb), and loop thru it creating named (you give it an initial name) color declarations in RGBA with alpha from .1 - 1 incrementing by .1. Output above would be: .c-blue-1 { color: rgba(0, 0, 255, 0.1); } .c-blue-2 { color: rgba(0, 0, 255, 0.2); } .c-blue-3 { color: rgba(0, 0, 255, 0.3); } .c-blue-4 { color: rgba(0, 0, 255, 0.4); } .c-blue-5 { color: rgba(0, 0, 255, 0.5); } .c-blue-6 { color: rgba(0, 0, 255, 0.6); } .c-blue-7 { color: rgba(0, 0, 255, 0.7); } .c-blue-8 { color: rgba(0, 0, 255, 0.8); } .c-blue-9 { color: rgba(0, 0, 255, 0.9); } .c-blue-10 { color: blue; } .c-red-1 { color: rgba(237, 20, 20, 0.1); } .c-red-2 { color: rgba(237, 20, 20, 0.2); } .c-red-3 { color: rgba(237, 20, 20, 0.3); } .c-red-4 { color: rgba(237, 20, 20, 0.4); } .c-red-5 { color: rgba(237, 20, 20, 0.5); } .c-red-6 { color: rgba(237, 20, 20, 0.6); } .c-red-7 { color: rgba(237, 20, 20, 0.7); } .c-red-8 { color: rgba(237, 20, 20, 0.8); } .c-red-9 { color: rgba(237, 20, 20, 0.9); } .c-red-10 { color: #ed1414; } .c-absurd-1 { color: rgba(20, 237, 20, 0.1); } .c-absurd-2 { color: rgba(20, 237, 20, 0.2); } .c-absurd-3 { color: rgba(20, 237, 20, 0.3); } .c-absurd-4 { color: rgba(20, 237, 20, 0.4); } .c-absurd-5 { color: rgba(20, 237, 20, 0.5); } .c-absurd-6 { color: rgba(20, 237, 20, 0.6); } .c-absurd-7 { color: rgba(20, 237, 20, 0.7); } .c-absurd-8 { color: rgba(20, 237, 20, 0.8); } .c-absurd-9 { color: rgba(20, 237, 20, 0.9); } .c-absurd-10 { color: #14ed14; } SASSmeister demo: http://www.sassmeister.com/gist/39577ef556de22a9acfe934cbc108a4e
resizing per storyboard issue swift
I am wondering if someone can show me how to write this code so it resizes automatically for different screen sizes. I have 4 storyboards with different screen sizes and just want a way to show the code, if this storyboard then (numbers change) follow this code, else (numbers chafe according to storyboard size) this code. I already tried resizing by adding to each axis number for example / 568 * size.frame.height after each y and height axis and same for x and width of course, but the code becomes too long and complex to read. Ideally I'd like an if statement saying if this screen size then it's storyboard 'this' then go to this code.. pianoButtonsWaterDropFrames = [ cNote: (CGRect(x: 33 , y: 40 , width: 20, height: 35), CGRect(x: 33, y: 360, width: 20, height: 35)), dNote: (CGRect(x: 66 , y: 42 , width: 20, height: 35), CGRect(x: 66, y: 360, width: 20, height: 35)), eNote: (CGRect(x: 99 , y: 41 , width: 20, height: 35), CGRect(x: 99 , y: 360, width: 20, height: 35)), fNote: (CGRect(x: 132, y: 48, width: 20, height: 35), CGRect(x: 132, y: 360, width: 20, height: 35)), gNote: (CGRect(x: 165, y: 39, width: 20, height: 35), CGRect(x: 165, y: 360, width: 20, height: 35)), aNote: (CGRect(x: 198, y: 57, width: 20, height: 35), CGRect(x: 198, y: 360, width: 20, height: 35)), bNote: (CGRect(x: 231, y: 60, width: 20, height: 35), CGRect(x: 231, y: 360, width: 20, height: 35)), cFourNote: (CGRect(x: 263, y: 54, width: 20, height: 35), CGRect(x: 263, y: 360, width: 20, height: 35)) ] Any help would be appreciated !
You can use HAS answer in this question to check, which iPhone your app is running on. Then you can use a switch statement and call different methods: let modelName = UIDevice.currentDevice().modelName switch modelName{ case "iPhone 3G", "iPhone 3GS": method1() case "iPhone 4", "iPhone 4S": method2() default: println("no size found") }
The property of maxWidth does not work for the Chinese words
$('canvas').drawText({ fillStyle: '#36c', fontStyle: 'bold', fontSize: '20pt', fontFamily: 'Trebuchet MS, sans-serif', text: '一二三四五六七八九十,一二三四五六七八九十,一二三四五六七八九十,一二三四五六七八九十,一二三四五六七八九十,一二三四五六七八九十,一二三四五六七八九十,一二三四五六七八九十,一二三四五六七八九十,一二三四五六七八九十,一二三四五六七八九十。', x: 50, y: 50, maxWidth: 300 }); In the above example, "text wrap" is not working for the Chinese words. How do I solve this problem?
How could I draw a line inside several shapes in KineticJS?
In my application I have several shapes that intersect with each other, for example, Shape A, Shape B and Shape C. A need to draw a polyline from Shape A to Shape C through Shape B, so the line lies inside all the shapes and crosses them almost at center. What is the most efficient way to implement this? Here is the code of example: http://jsfiddle.net/dselkirk/ZMUkE/. I need to draw a yellow line, but not manually: var stage = new Kinetic.Stage({ container: 'container', width: 850, height: 750 }); var layer = new Kinetic.Layer({ x: 0, y: 0 }); var rect = new Kinetic.Rect({ x: 100, y: 100, width: 80, height: 60, fill: '#E67E22' }); var rect2 = new Kinetic.Rect({ x: 640, y: 70, width: 40, height: 70, fill: '#3498DB', }); var circle = new Kinetic.Circle({ x: 600, y: 150, radius: 70, fill: '#2ECC71', }); var polyOne = new Kinetic.Polygon({ x: 80, y: 100, points: [73, 192, 73, 160, 340, 23, 500, 109, 499, 139, 342, 93], fill: '#9B59B6' }); var polyTwo = new Kinetic.Polygon({ x: 100, y: 160, points: [-5, 0, 75, 0, 70, 10, 70, 60, 60, 90, 61, 92, 64, 96, 66, 100, 67, 105, 67, 110, 67, 113, 66, 117, 64, 120, 63, 122, 61, 124, 58, 127, 55, 129, 53, 130, 50, 130, 20, 130, 17, 130, 15, 129, 12, 127, 9, 124, 7, 122, 6, 120, 4, 117, 3, 113, 3, 110, 3, 105, 4, 100, 6, 96, 9, 92, 10, 90, 0, 60, 0, 10], fill: '#e74c3c' }); var imageObj = new Image(); imageObj.onload = function () { var yoda = new Kinetic.Image({ x: 120, y: 120, image: imageObj, width: 15, height: 18 }); // add the shape to the layer layer.add(yoda); stage.add(layer); }; imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/yoda.jpg'; var imageObj2 = new Image(); imageObj2.onload = function () { var dart = new Kinetic.Image({ x: 650, y: 80, image: imageObj2, width: 20, height: 21 }); layer.add(dart); stage.add(layer); }; var yellowLine = new Kinetic.Line({ points: [{x:125,y:140},{x:125,y:280}, {x:425,y:150}, {x:555,y:220}, {x:655,y:100}], stroke: 'yellow', strokeWidth: 2, lineJoin: 'round', dashArray: [33, 10] }); layer.add(polyOne); layer.add(polyTwo); layer.add(yellowLine); layer.add(circle); layer.add(rect); layer.add(rect2); stage.add(layer); yellowLine.moveToTop(); For now I think the algorithm should be: 1) Find intersection points of all shapes. 2) Draw lines between these intersectiopn points. If any line point lies outside the shape - move it horizontally/vertically till it lies inside the shape. But this algorithm seems not efficient at all.