Как избежать искажения пути svg при transition морфинга svg?
У меня есть следующий SVG, созданный в inkscape
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="345.70975"
height="352.91309"
viewBox="0 0 91.469035 93.374923"
version="1.1"
id="svg8"
inkscape:version="0.92.2 5c3e80d, 2017-08-06"
sodipodi:docname="double-square.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.70710678"
inkscape:cx="226.41877"
inkscape:cy="36.880616"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:pagecheckerboard="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1440"
inkscape:window-height="801"
inkscape:window-x="0"
inkscape:window-y="1"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-21.120772,-24.484056)">
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#800080;stroke-width:1.29393971;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 22.242817,24.963907 h 89.459313 c 0.10307,0 0.18605,0.08678 0.18605,0.194558 v 92.051005 c 0,0.10779 -0.0829,0.19456 -0.18605,0.19456 H 22.242817 c -0.103073,0 -0.186053,-0.0867 -0.186053,-0.19456 V 25.158465 c 0,-0.107785 0.08299,-0.194558 0.186053,-0.194558 z"
id="rect818"
inkscape:connector-curvature="0" />
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#ff0000;stroke-width:1.31637728;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 96.672725,103.80812 c -22.695046,9.46462 -52.584739,24.28389 -62.190302,0.78977 -9.605563,-23.494119 -20.853186,-57.321821 1.841865,-66.786436 22.695046,-9.464613 57.771554,-23.161339 67.377122,0.332775 9.60556,23.494112 15.66636,56.199275 -7.028685,65.663891 z"
id="path815"
inkscape:connector-curvature="0"
sodipodi:nodetypes="sssss" />
</g>
</svg>
Теперь, когда я использую anime.js для преобразования этого svg из квадрата в квадрат с закругленными углами, я вижу, что квадрат довольно сильно искажен, и переход в квадрат не совсем правильный.
let shapes = [
{
d: "m 22.242817,24.963907 h 89.459313 c 0.10307,0 0.18605,0.08678 0.18605,0.194558 v 92.051005 c 0,0.10779 -0.0829,0.19456 -0.18605,0.19456 H 22.242817 c -0.103073,0 -0.186053,-0.0867 -0.186053,-0.19456 V 25.158465 c 0,-0.107785 0.08299,-0.194558 0.186053,-0.194558 z"
},
{
d: "m 96.672725,103.80812 c -22.695046,9.46462 -52.584739,24.28389 -62.190302,0.78977 -9.605563,-23.494119 -20.853186,-57.321821 1.841865,-66.786436 22.695046,-9.464613 57.771554,-23.161339 67.377122,0.332775 9.60556,23.494112 15.66636,56.199275 -7.028685,65.663891 z"
}
]
var morph1 = anime({
targets: '.square-path',
d: [
{value: shapes[0].d},
{value: shapes[1].d}
],
duration: 3000,
direction: 'alternate',
autoplay: true,
easing: 'linear',
elasticity: 100,
loop: true
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="345.70975"
height="352.91309"
viewBox="0 0 91.469035 93.374923"
version="1.1"
id="svg8"
inkscape:version="0.92.2 5c3e80d, 2017-08-06"
sodipodi:docname="double-square.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.70710678"
inkscape:cx="226.41877"
inkscape:cy="36.880616"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:pagecheckerboard="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1440"
inkscape:window-height="801"
inkscape:window-x="0"
inkscape:window-y="1"
inkscape:window-maximized="1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-21.120772,-24.484056)">
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#800080;stroke-width:1.29393971;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 22.242817,24.963907 h 89.459313 c 0.10307,0 0.18605,0.08678 0.18605,0.194558 v 92.051005 c 0,0.10779 -0.0829,0.19456 -0.18605,0.19456 H 22.242817 c -0.103073,0 -0.186053,-0.0867 -0.186053,-0.19456 V 25.158465 c 0,-0.107785 0.08299,-0.194558 0.186053,-0.194558 z"
id="rect818"
class="square-path"
inkscape:connector-curvature="0" />
</g>
</svg>
Как мне избежать искаженного квадрата при transition морфинга SVG?
Свободный перевод вопроса How do i avoid the mangled svg path in the svg morph transition? от участника @Alexander Solonik.
Ответы (1 шт):
- Убедитесь, что ваши две формы имеют одинаковую сумму сегментов и типы сегментов.
На самом деле это правило SVG, но мне кажется, что anime.js поможет вам обойти это правило. Но лучше контролировать это самостоятельно, чем полагаться на программу, которая угадывает ваши намерения.
Ваш начальный путь состоит из 8 или 9 сегментов пути:
m 22.242817,24.963907
h 89.459313
c 0.10307,0 0.18605,0.08678 0.18605,0.194558
v 92.051005
c 0,0.10779 -0.0829,0.19456 -0.18605,0.19456
H 22.242817
c -0.103073,0 -0.186053,-0.0867 -0.186053,-0.19456
V 25.158465
c 0,-0.107785 0.08299,-0.194558 0.186053,-0.194558
z
Но ваш начальный path содержит только четыре сегмента
m 96.672725,103.80812
c -22.695046,9.46462 -52.584739,24.28389 -62.190302,0.78977
c -9.605563,-23.494119 -20.853186,-57.321821 1.841865,-66.786436
c 22.695046,-9.464613 57.771554,-23.161339 67.377122,0.332775
c 9.60556,23.494112 15.66636,56.199275 -7.028685,65.663891
z
- Расположите точки контура так, чтобы они располагались близко к тому месту, где вы хотите, чтобы они попали в другую форму.
Например, при переходе от круга к квадрату сделайте круг с четырьмя точками и разместите четыре точки на северо-западе, северо-востоке, юго-западе и юго-востоке.
Если вместо этого они находятся в случайных (далёких) положениях относительно другой формы, вы получите анимацию, которая появится, чтобы связать себя , а затем разложить себя на отдельные части.
В приведенном ниже примере оба пути имеют ровно четыре команды пути кривой Безье (c). И их конечные точки расположены близко к соответствующему положению на другой фигуре.
let shapes = [
{
d: "M 20, 20 c 100,0 200,0 300,0 c 0,100 0,200 0,300 c -100,0 -200,0 -300,0 c 0,-100 0,-200 0,-300 z"
},
{
d: "M 89.289322,89.289322 c 42.392448,-38.369033 104.952908,-35.372751 141.421358,0 39.05243,39.052428 39.05243,102.368928 0,141.421358 -39.05243,39.05243 -102.36893,39.05243 -141.421358,0 -39.05243,-39.05243 -39.052429,-102.36893 0,-141.421358 z"
}
]
var morph1 = anime({
targets: '.square-path',
d: [
{value: shapes[0].d},
{value: shapes[1].d}
],
duration: 3000,
direction: 'alternate',
autoplay: true,
easing: 'linear',
elasticity: 100,
loop: true
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<svg
width="345.70975"
height="352.91309"
viewBox="0 0 340 340"
id="svg8">
<g
id="layer1">
<path
style="opacity:1;fill:none;fill-opacity:1;stroke:#800080;stroke-width:1.29393971;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="M 20, 20 c 100,0 200,0 300,0 c 0,100 0,200 0,300 c -100,0 -200,0 -300,0 c 0,-100 0,-200 0,-300 z"
id="rect818"
class="square-path" />
</g>
</svg>
Свободный перевод ответа от участника @Paul LeBeau.
