I am playing around with a cool effect that I found on codepen here:
https://codepen.io/P3R0/pen/zxabvb
I want to make the dashes on this svg animation shorter, and believe I have found the css element which does this:
stroke-dasharray: 70 330;
When I reduce 70 to 30 for example, the dashes become shorter which is good. However you will notice they no longer glide around smoothly - they now jump position.
I've been searching and trying to understand how stoke-dasharray works, but can't work it out. Can anyone explain to me how these numbers work and how I can make shorter dashes which still glide around smoothly.
Thanks for any help.
stroke-dasharray's confused me for a long time. Until I finally figured it out.
I made a full codepen that explains it with examples. https://codepen.io/joshdance-the-sans/pen/oNqzRym
If you read the docs stroke-dasharray: "specify the lengths of alternating dashes and gaps. If an odd number of values is provided, then the list of values is repeated to yield an even number of values.
So the numbers are just a repeating list of: dash length, gap length, dash length, gap length
Which is repeated around the whole shape.
In your example:
stroke-dasharray: 70 330;
70 is the dash length, and 330 is the gap length. This makes sense because there are 5 different colors, which is done by copying the SVG 5 times, and adding a different stroke color to each. Stroke length + gap length is 70 + 330 = 400 and they are offsetting the strokes by 400 in the keyframes.
#keyframes stroke {
100% {
stroke-dashoffset: -400;
}
}
Your example is cool, but complex as it has animation as well as multiple different strokes. Check out my codepen and play with the CSS for a simpler example to understand. Good luck!
The first parameter of the stroke-dasharray is the length of the filled area and the second one is the total length of the shape. You can fix your animation by shortening the total length as below.
stroke-dasharray: <filled-length> <total-length>;
stroke-dasharray: 30 150;
Related
I have a gradient color scale that I want to define a set of classes for.
To break it down I have a value that can span between 0 and 8.5 with a step of 0.25. I have a total of 34 different colors (8.5/0.25 = 34) that I want to span within this gradient color scale. So I need to define 34 different classes each a tad more down the scale depending value that I have in my database. So if I find a value of 2.25 I want to get the color 29.4% ((2.25 * 100 /) 8.5 = 29.4) within my gradient scale. How can I do this by using css classes?
My reason for doing this is to add color to icons that I place on my map. The values are speed and based on the speed I need to add a class to my icon on the map that contains a background (color) that matches the "value" of the speed?
I have tried googling for the past 30 minutes, but I have found my self unable to find anything that I can use.
If this seems quite intuitive I am willing to try other solutions that can assist me in achieving what I need.
If it is of any importance I am using MapBox as my map solution.
Try using SCSS. In SCSS you can use variables and math.
I'm not very good with radial calculations, I can't imagine thus I can't be sure. I need some explanation of Math.atan2() thing, please.
Usual task - to make an object rotate after the mouse. I get the differences, get the angle, I see angles in the text areas and DIRECTLY the object does follow the mouse. What I need now is everything to be smooth. I need angles to be 0-360 but after 180 object rotation becomes -180 and counts backwards, and mouse rotation becomes -90 after 270 and also counts back to 0.
More deeply, I want a smooth rotation, it means a set speed of say 2 per frame, to meet the mouse angle the shortest way. It takes to set conditions and I can't do that cause I don't even understand the logic of these values. They are almost random! I don't need it to be done or copied, I need to understand to move on so if you could please explain how does it work and what I do wrong...
Code is simple:
angle = Math.atan2(deltaY,deltaX)/(Math.PI/180) + 90; //+90 cause it lacks it to look at the mouse//
Object01.rotation = angle;
So the problem is I don't even get how it works... if 2 values are different the object can't point at the mouse but it does. Numbers lie and if I need something based on these numbers it will be wrong. Very wrong... Need organization. Meaning I want everything to be ready for further coding that will be based on the rotations to not jump up and down cause of misfit ends.
Add: Explanation of how does it happen, what I described above. Why such a chaos of the values? And an advice on how could I arrange it for further coding, just as I said. Animation alone wont work if I want to make rotation an element of important events such as shooting direction and aiming speed. Or changes of speed rotation of a lockpicked lock. Or anything much more complicated that wont work if I don't make straight and clear values: from A to Z, from 1 to 10, no 8s between 2 and 3, no R before B, no mouse angle 270 when object facing it -90 when they both started from 0 and reached 180 together.
Oh, and as I said, mouse facing works but when I try to make a certain speed of chasing mouse the shortest way it turns the object wrong directions in all 4 quarters. I assume it's also about this arctangens thing that has issues with delta values becoming negative in different quarters. And when I change it, some other value goes wrong... So I need to know exactly what I'm doing to know what's wrong and how to fix it. So yep. Need explanation. Please.
Add2: angleZ = Math.atan2(oppSide,adjSide)/(Math.PI/180);
So I divided rotation to 4 quarters, for each I count atan as opp. side to adj. side, then add 90, 180 and 270 respectively. My mouse rotation does 360, but the object that follow through simple object.rotation = angleZ; still goes to 180, then from -180 to 0 on the left side. Why does it ignore the simple command? The rotation fits but I need it to be equal, no surprises! Why is it happening? How can a number I directly set to be equal to another number as a base of the action change itself to the one of same rotation but completely different number? It doesn't even know it's degrees! It's as simple as "object.rotation, please be equal to the number I choose!"
It's just different coordinate systems. Like how x starts at 0 at the left of the stage, goes +x to the right, and -x to the left, object rotation starts at 0˚ pointing up, and goes +180˚ clockwise and -180˚ anti-clockwise.
Math.atan2 happens to start at 0 pointing left (-x), and go +270˚ clockwise and -90˚ anti-clockwise, which is annoying, but it just means you have to convert between coordinate systems by adding 90˚.
You can spin something around over and over of course, so the numbers jump so that they always stay within the same range, because 361˚ is the same as 1˚, and -270˚ is the same as 90˚. You can tell an object to rotate outside of the -180˚ to 180˚ range, and it will normalise the rotation to within those values.
As mitim described, to smoothly animate rotation you'll either need to use Event.ENTER_FRAME, a Timer, or a tweening library like TweenLite. Most tweening libraries can work out the shortest rotation direction for you, but otherwise you can simply calculate both and see which is smaller.
As an idea, since it seems like you know the angle you need to rotate towards and it's direction, would it be easier to just animate towards that angle to get your smooth rotation? Basically treat it like any other animatable property and just add on your rotation speed (2 degrees it looks like) per frame tick, until it reaches the desired rotation.
Find angle amount needed to rotate by
Figure out if clockwise or counter clockwise direction and set the rotation amount. This can be figured out by checking if the angle is great then 180 / positive or negative
Add the rotation amount * direction every frame tick, until the desired rotation is less then or equal to the rotation amount per frame
Set rotation to desired rotation
I'm developing a simple a graphical editor for my flash-based app. In my editor there's a posibility of scaling, range of scaling is big (maximum scale is 16.0, minimum scale is 0.001 and default scale is 0.2). So it's quite possible that a user can draw a line with thickness 0.1 or 300.0, and it looks that line possible thickness (in Graphics.lineStyle()) has upper border. As I found out from livedocs maximum value is 255. So if thickness is greater then 255.0 there'is drawn a line of thickness 255.0. Whether mentioned upper border exists and how big is it. Here're my questions:
Right now I'm drawing lines with drawPath() or lineTo() methods. Natural walkarround if thickness is greater then 255.0 is to draw a rectange instead of segment and two circles on the ends of segment (instead of lineTo()). Or even to draw two thin segments and two half-circles and fill interior. Maybe there's more elegant/quick solution?
Another question is if the thickness of line is big but less then 255.0 (e.g. 100.0), what is faster drawing a line with lineTo() or drawing two thin segments and two half-circles and fill interior?
And finally, maybe someone knows a good article/book where I can read what's inside all methods of flash.display.Graphics class (or even not flash specific article/book on graphics)?
Any thoughts are appreciated. Thank you in advance!
I agree with f-a that putting the line in a container would probably be better and more efficient than drawing a rectangle and extra circles.
I don't think that the math would be too difficult to work out. For efficiency you should probably only do this if the line style is going to be over 255.
To setup the display object to hold your line I would start by halving the width of your line (the length can stay the same). Then create a new sprite and draw the line in the sprite at half size (e.g. if you wanted 300, just draw it at 150). It would be most simple to just start at (0,0) and draw the segment straight so that all of your transformations can be applied to the new sprite.
From here you can just double the scaleY of the sprite to get the desired line weight. It should keep the same length and the ends should also be rounded correctly.
Hope this helped out!
A cool resource for working with the graphics class is Flash and Math. This site has several cool effects and working examples and source code.
http://www.flashandmath.com/
I'm drawing line graphs on a canvas. The lines draw fine. The graph is scaled, every segment is drawn, color are ok, etc. My only problem is visually the line width varies. It's almost like the nib of a caligraphy pen. If the stroke is upward the line is thin, if the stroke is horizontal, the line is thicker.
My line thickness is constant, and my strokeStyle is set to black. I don't see any other properties of the canvas that affect such a varying line width but there must be.
Javascript:
var badCanvas = document.getElementById("badCanvas"),
goodCanvas = document.getElementById("goodCanvas"),
bCtx = badCanvas.getContext("2d"),
gCtx = goodCanvas.getContext("2d");
badCanvas.width = goodCanvas.width = badCanvas.height = goodCanvas.height = 300;
// Line example where the lines are blurry weird ect.
// Horizontal
bCtx.beginPath();
bCtx.moveTo(10,10);
bCtx.lineTo(200,10);
bCtx.stroke();
//Verticle
bCtx.beginPath();
bCtx.moveTo(30,30);
bCtx.lineTo(30,200);
bCtx.stroke();
// Proper way to draw them so they are "clear"
//Horizontal
gCtx.beginPath();
gCtx.moveTo(10.5,10.5);
gCtx.lineTo(200.5,10.5);
gCtx.stroke();
//Verticle
gCtx.beginPath();
gCtx.moveTo(30.5,30);
gCtx.lineTo(30.5,200);
gCtx.stroke();
// Change the line width
bCtx.lineWidth = 4;
gCtx.lineWidth = 4;
// Line example where the lines are blurry weird ect.
// Horizontal
bCtx.beginPath();
bCtx.moveTo(10,20.5);
bCtx.lineTo(200,20.5);
bCtx.stroke();
//Verticle
bCtx.beginPath()
bCtx.moveTo(50.5,30);
bCtx.lineTo(50.5,200);
bCtx.stroke();
// Proper way to draw them so they are "clear"
//Horizontal
gCtx.beginPath();
gCtx.moveTo(10,20);
gCtx.lineTo(200,20);
gCtx.stroke();
//Verticle
gCtx.beginPath();
gCtx.moveTo(50,30);
gCtx.lineTo(50,200);
gCtx.stroke();
HTML:
<h2>BadCanvas</h2>
<canvas id="badCanvas"></canvas>
<h2>Good Canvas</h2>
<canvas id="goodCanvas"></canvas>
CSS:
canvas{border:1px solid blue;}
Live Demo
My live demo basically just recreates what the MDN says. For even stroke widths you can use integers for coordinates, for odd stroke widths you want to use .5 to get crisp lines that fill the pixels correctly.
From MDN Article
If you consider a path from (3,1) to (3,5) with a line thickness of
1.0, you end up with the situation in the second image. The actual
area to be filled (dark blue) only extends halfway into the pixels on
either side of the path. An approximation of this has to be rendered,
which means that those pixels being only partially shaded, and results
in the entire area (the light blue and dark blue) being filled in with
a color only half as dark as the actual stroke color. This is what
happens with the 1.0 width line in the previous example code.
To fix this, you have to be very precise in your path creation.
Knowing that a 1.0 width line will extend half a unit to either side
of the path, creating the path from (3.5,1) to (3.5,5) results in the
situation in the third image — the 1.0 line width ends up completely
and precisely filling a single pixel vertical line.
If linewidth is an odd number, just add 0.5 to x or y.
I just solved a problem of a similar nature. It involved a bug in a For loop.
PROBLEM: I had created a for loop to create a series of connected line segments and noticed that the line was thick to start but thinned out significantly by the final segment (no gradients were explicitly used).
FIRST, DEAD END THOUGHT: At first I assumed it was the above pixel issue, but the problem persisted even after forcing all the segments to remain at a constant level.
OBSERVATION: I noticed that I made a newbie's mistake -- I only used a single "ctx.beginPath()" and "ctx.moveTo(posX,posY)" PRIOR to the For loop and a single "ctx.stroke()" AFTER the For loop and the loop itself wrapped a single ctx.lineTo().
SOLUTION: Once I moved all methods (.beginPath(), .moveTo(), .lineTo() and .stroke()) together into the For loop so they would all be hit on each iteration, the problem went away. My connected line had the desired uniform thickness.
Try lineCap = "round" and lineJoin = "round". See "Line Styles" in this PDF to see what these parameters do.
Edit 17-July-2015: Great cheat sheet, but the link is dead. As far as I can tell, there's a copy of it at http://www.cheat-sheets.org/saved-copy/HTML5_Canvas_Cheat_Sheet.pdf.
In Flash, pixels are calculated using twips, or twentieth of a pixel. Consequently, every position is always in multiples of 0.05. I haven't seen this mentioned in the HTML Canvas spec and am unable to trace the cursor position on Canvas. Does anyone know the accuracy of its pixel calculations?
Edit for clarification:
I'm referring more to Zeno's paradox which says in order to move something from point A to point B, it must first move to a point halfway between the two. And then halfway again, ad infinitum.
So if I want to move on the x axis from point 0 to 100 at 0.5:
At frame 1: 50
Frame 2: 75
Frame 3: 87.5
Then: 93.75, 96.875, 98.4375... etc.
So at what step does the Canvas actually round-up to the next pixel?
I'm unsure what you mean by accuracy of slicing.
Pixels on the Canvas can be drawn to a little less than 0.10, after which they make barely any visible impact.
Of course, if you scale, you can draw things that are 0.00125 pixels, and so on. But they won't be visible if you unscale.
http://jsfiddle.net/GvVD9/
(That first square block on the top-left is a pixel)
Accuracy of the mouse is an entirely different thing, in no way related to the canvas spec.
EDIT:
Well, we can sorta demonstrate that. We can draw a bunch of pixels with y values approaching 100 and see how they compare to a red pixel drawn with the y value 100.
http://jsfiddle.net/GvVD9/46/
Every single horizontally separated piece is just a single 1 by 1 pixel rect using the drawRect command.
50
75
87.5
93.75 // first black pixel you see in image
96.875
98.4375
99.21875
99.609375
99.8046875
99.90234375
99.951171875
99.9755859375
99.98779296875
99.993896484375
99.9969482421875 // last black pixel you see in image