SVG stroke-dasharray offset not consistent

走远了吗. 提交于 2019-12-03 10:37:11

I think that there are 2 slight mistakes in your setup.

The first is that the spacing of your dots is the sum of the 2 parameters to the stroke-dash array. Since the first parameter is always 0.001, the second one should be the result of your formula minus 0.001.

The second one is that you are placing 36 dots around the circle. That gives 10 degrees for the angle from dot to dot. So, your animations should specificy 10deg, 20deg, 30deg for the series, and not 15deg 30deg 45deg ... That creates a jump of 5 deg at the end of every cycle.

I think that I have it more or less working

fiddle

There was also an issue with the initial rotation; I hope that now it is what you wanted.

And also, there was some kind of round up due to the small size of the svg; setting it to 600 square works much better.

I have also added a line at 10 deg to check the correct alignment of the dots.

CSS

body {
    background: black;
    padding: 0;
    margin: 0;
}
circle {
    fill: none;             
    stroke-width: 10;
    stroke-linecap: round;
}
circle { -webkit-transform-origin: center center; -moz-transform-origin: center center; transform-origin: center center;
  -webkit-animation-duration: 3s; 
-webkit-animation-timing-function: ease-in-out;
-webkit-animation-iteration-count: infinite;}
circle:nth-child(2)  { -webkit-animation-name:second; 
                       -moz-animation:second  3s ease-in-out infinite; 
                       animation:second  3s ease-in-out infinite;}
circle:nth-child(3)  { -webkit-animation-name:third; -moz-animation:third   3s ease-in-out infinite; animation:third   3s ease-in-out infinite; }
circle:nth-child(4)  { -webkit-animation-name:fourth; -moz-animation:fourth  3s ease-in-out infinite; animation:fourth  3s ease-in-out infinite; }
circle:nth-child(5)  { -webkit-animation-name:fifth; -moz-animation:fifth   3s ease-in-out infinite; animation:fifth   3s ease-in-out infinite; }
circle:nth-child(6)  { -webkit-animation-name:sixth; -moz-animation:sixth   3s ease-in-out infinite; animation:sixth   3s ease-in-out infinite; }
circle:nth-child(7)  { -webkit-animation-name:seventh; -moz-animation:seventh 3s ease-in-out infinite; animation:seventh 3s ease-in-out infinite; }
circle:nth-child(8)  { -webkit-animation-name:eighth; -moz-animation:eighth  3s ease-in-out infinite; animation:eighth  3s ease-in-out infinite; }
circle:nth-child(9)  { -webkit-animation-name:ninth; -moz-animation:ninth   3s ease-in-out infinite; animation:ninth   3s ease-in-out infinite; }
circle:nth-child(10) { 
    -webkit-animation-name:tenth; 
    -moz-animation:tenth   3s ease-in-out infinite; 
    animation:tenth   3s ease-in-out infinite; 
    -webkit-transform: rotate(10deg);}
@-webkit-keyframes second {   0% { -webkit-transform:rotate(5deg)  }
                            100% { -webkit-transform:rotate(15deg) } }
@-webkit-keyframes third {  100% { -webkit-transform:rotate(20deg) } }
@-webkit-keyframes fourth  {  0% { -webkit-transform:rotate(5deg)  }
                            100% { -webkit-transform:rotate(35deg) } }
@-webkit-keyframes fifth {  100% { -webkit-transform:rotate(40deg) } }
@-webkit-keyframes sixth   {  0% { -webkit-transform:rotate(5deg)  }
                            100% { -webkit-transform:rotate(55deg) } }
@-webkit-keyframes seventh {100% { -webkit-transform:rotate(60deg) } }
@-webkit-keyframes eighth  {  0% { -webkit-transform:rotate(5deg)  }
                            100% { -webkit-transform:rotate(75deg) } }
@-webkit-keyframes ninth  {   0% { -webkit-transform:rotate(0deg)  }
                            100% { -webkit-transform:rotate(80deg) } }
@-webkit-keyframes tenth  {   0% { -webkit-transform:rotate(5deg)  }
                            100% { -webkit-transform:rotate(95deg) } }
@-moz-keyframes second  {   0% { -moz-transform:rotate(5deg)  }
                          100% { -moz-transform:rotate(15deg)  } }
@-moz-keyframes third   { 100% { -moz-transform:rotate(20deg)  } }
@-moz-keyframes fourth  {   0% { -moz-transform:rotate(5deg)  }
                          100% { -moz-transform:rotate(35deg)  } }
@-moz-keyframes fifth   { 100% { -moz-transform:rotate(40deg)  } }
@-moz-keyframes sixth   {   0% { -moz-transform:rotate(5deg)  }
                          100% { -moz-transform:rotate(55deg)  } }
@-moz-keyframes seventh { 100% { -moz-transform:rotate(60deg)  } }
@-moz-keyframes eighth  {   0% { -moz-transform:rotate(5deg)  }
                          100% { -moz-transform:rotate(75deg) } }
@-moz-keyframes ninth   { 100% { -moz-transform:rotate(80deg) } }
@-moz-keyframes tenth   {   0% { -moz-transform:rotate(5deg)  }
                          100% { -moz-transform:rotate(95deg) } }

line {
    stroke-width: 1;
    -webkit-transform-origin: left center;
    -webkit-transform: rotate(-10deg);
}

And also optimized a little bit the styles

Well, after a lot of time spent with that issue, I am almost sure that there is some kind of bug in some kind of rounding / precision.

I have changed the idea fully to avoid this issue. The target will be to have the circles make full circles before ending the animation, so that the beginning and the end of the animation are always in sync.

Since that generates an huge keyframes style, I want to reuse it; to achieve this I have grouped the circles in a nested way; and applied the animation to every group:

HTML

<svg viewBox="0 0 60 60">
    <g class="g">
    <circle cx="30" cy="30" r="10" stroke-dasharray="0.001, 1.745" stroke="hsl(120, 100%, 50%)"/>
    <g class="g">
    <circle cx="30" cy="30" r="12" stroke-dasharray="0.001, 2.094" stroke="hsl(108, 100%, 50%)" class="c2"/>
    <g class="g">
    <circle cx="30" cy="30" r="14" stroke-dasharray="0.001, 2.443" stroke="hsl(96, 100%, 50%)"/>
    <g class="g">
    <circle cx="30" cy="30" r="16" stroke-dasharray="0.001, 2.793" stroke="hsl(84, 100%, 50%)"  class="c2"/>
    <g class="g">
    <circle cx="30" cy="30" r="18" stroke-dasharray="0.001, 3.142" stroke="hsl(72, 100%, 50%)"/>
    <g class="g">
    <circle cx="30" cy="30" r="20" stroke-dasharray="0.001, 3.491" stroke="hsl(60, 100%, 50%)" class="c2"/>
    <g class="g">
    <circle cx="30" cy="30" r="22" stroke-dasharray="0.001, 3.840" stroke="hsl(48, 100%, 50%)"/>
    <g class="g">
     <circle cx="30" cy="30" r="24" stroke-dasharray="0.001, 4.189" stroke="hsl(36, 100%, 50%)"  class="c2"/>
    <g class="g">
    <circle cx="30" cy="30" r="26" stroke-dasharray="0.001, 4.538" stroke="hsl(24, 100%, 50%)"/>
    <g class="g">
    <circle cx="30" cy="30" r="28" stroke-dasharray="0.001, 4.887" stroke="hsl(12, 100%, 50%)"  class="c2"/>
    </g></g></g></g></g></g></g></g></g></g>
</svg>

(yes, back to the low resolution !)

CSS

body {
    background: black;
    padding: 0;
    margin: 0;
}

circle {
    fill: none;             
    stroke-width: 1;
    stroke-linecap: round;
}

.g { 
    -webkit-transform-origin: center center; -moz-transform-origin: center center;                                         transform-origin: center center;
    -webkit-animation-duration: 108s; 
    -webkit-animation-timing-function: ease-in-out;
    -webkit-animation-iteration-count: infinite; 
    -webkit-animation-name: anim; 
    -moz-animation:second  3s ease-in-out infinite; 
     animation:second  3s ease-in-out infinite;}

.c2 {
    -webkit-transform-origin: center center;
    -webkit-transform: rotate(5deg); 
} 

@-webkit-keyframes anim {   0% { -webkit-transform:rotate(0deg)}
                        2.778% { -webkit-transform:rotate(10deg)}
                        5.56% { -webkit-transform:rotate(20deg)}
                        8.33% { -webkit-transform:rotate(30deg)}
                       11.11% { -webkit-transform:rotate(40deg)}
                       13.89% { -webkit-transform:rotate(50deg)}
                       16.67% { -webkit-transform:rotate(60deg)}
                       19.44% { -webkit-transform:rotate(70deg)}
                       22.22% { -webkit-transform:rotate(80deg)}
                       25% { -webkit-transform:rotate(90deg)}
                       27.78% { -webkit-transform:rotate(100deg)}
                       30.56% { -webkit-transform:rotate(110deg)}
                       33.33% { -webkit-transform:rotate(120deg)}
                       36.11% { -webkit-transform:rotate(130deg)}
                       38.89% { -webkit-transform:rotate(140deg)}
                       41.67% { -webkit-transform:rotate(150deg)}
                       44.44% { -webkit-transform:rotate(160deg)}
                       47.22% { -webkit-transform:rotate(170deg)}
                       50%    { -webkit-transform:rotate(180deg)}
                       52.78% { -webkit-transform:rotate(190deg)}
                       55.56% { -webkit-transform:rotate(200deg)}
                       58.33% { -webkit-transform:rotate(210deg)}
                       61.11% { -webkit-transform:rotate(220deg)}
                       63.89% { -webkit-transform:rotate(230deg)}
                       66.67% { -webkit-transform:rotate(240deg)}
                       69.44% { -webkit-transform:rotate(250deg)}
                       72.22% { -webkit-transform:rotate(260deg)}
                       75%    { -webkit-transform:rotate(270deg)}
                       77.78% { -webkit-transform:rotate(280deg)}
                       80.56% { -webkit-transform:rotate(290deg)}
                       83.33% { -webkit-transform:rotate(300deg)}
                       86.11% { -webkit-transform:rotate(310deg)}
                       88.89% { -webkit-transform:rotate(320deg)}
                       91.67% { -webkit-transform:rotate(330deg)}
                       94.44% { -webkit-transform:rotate(340deg)}
                       97.22% { -webkit-transform:rotate(350deg)}
                     100%     { -webkit-transform:rotate(360deg)}
}

And new demo (Sorry, only webkit)

This is my attempt to investigate the errors. I have changed the system, instead of animation, I have 2 sets of circles, one in color and another in black over it, and rotated 10 deg. The color circles shouldn't show; the offset is a measure off the error. (may be you need to scroll to see the circles

offsets demo

I think the problem here is that the dashed line drawing algorithm uses a fast approximation of line length instead of actually integrating the path length along each segment, which would presumably be quite slow.

If you draw the dots as individual circles instead of using dashed lines, then this problem goes away. The following PHP script will do the calculations for you:

<svg viewBox="0 0 60 60">
<g transform="translate(30,30)">
<?php
define("PI",3.141592654);
for ($i=0; $i<10; $i++) {
  $r = 10 + 2 * $i;
  $hue = 120 - 12 * $i;
  echo "<g id=\"ring_$i\">\n";
  for ($th=0; $th<360; $th+=10) {
    $theta = ($th + 5 * $i) * PI / 180;
    $x = $r * sin($theta);
    $y = $r * cos($theta);
    printf("  <circle cx=\"%.5f\" cy=\"%.5f\" r=\"0.45\" fill=\"hsl(%d,100%%,50%%)\"/>\n",$x,$y,$hue);
  }
  echo "</g>\n";
}
?></g>
</svg>

And here's the CSS (vendor-specific rules omitted for brevity):

body { background: black; padding: 0; margin: 0; }
g#ring_0 { transform:rotate(5deg); }
g#ring_1 { animation:second 3s ease-in-out infinite; }
g#ring_2 { animation:third 3s ease-in-out infinite; }
g#ring_3 { animation:fourth 3s ease-in-out infinite; }
g#ring_4 { animation:fifth 3s ease-in-out infinite; }
g#ring_5 { animation:sixth 3s ease-in-out infinite; }
g#ring_6 { animation:seventh 3s ease-in-out infinite; }
g#ring_7 { animation:eighth 3s ease-in-out infinite; }
g#ring_8 { animation:ninth 3s ease-in-out infinite; }
g#ring_9 { animation:tenth 3s ease-in-out infinite; }
keyframes second { 100% { transform:rotate(10deg) } }
keyframes third { 100% { transform:rotate(20deg) } }
keyframes fourth { 100% { transform:rotate(30deg) } }
keyframes fifth { 100% { transform:rotate(40deg) } }
keyframes sixth { 100% { transform:rotate(50deg) } }
keyframes seventh { 100% { transform:rotate(60deg) } }
keyframes eighth { 100% { transform:rotate(70deg) } }
keyframes ninth { 100% { transform:rotate(80deg) } }
keyframes tenth { 100% { transform:rotate(90deg) } }

You can see it working here: JSFiddle

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!