繁体   English   中英

使用d3围绕自己的中心旋转svg路径

[英]Rotate an svg path around its own centre using d3

我有一个用Inkscape制作的SVG路径(开关图标),我试图以编程方式围绕其自身的中心旋转90度。 在我正确的网页中,我有许多图标都由ID引用,因此这是我可以应用的通用解决方案。

看起来这个问题是相同的,但是OP从来没有跟进,他们从来没有提供更多的代码或小提琴。

我在这里有一个小提琴它显示了我的示例的所有内容。

knob = d3.select("#switch1")
knob.attr('transform', 'rotate(0 0 0)')

是我用于轮换的基本代码。 我需要知道如何计算x和y值,以便可以像示例中一样使任何给定的图标指向打开/关闭文本。 或使用d3获得相同旋转效果的另一种方法

如果我执行了knob.attr('transform', 'rotate(90 0 0)')该图标就会从页面上消失-我以为0 0会绕其相对中心旋转?

如果我手动执行knob.attr('transform', 'rotate(90 15 15)') ,则可以将其保留在页面上,但放置在错误的位置。

SVG路径由以下组成:

       <path
       id="switch1"
       style="display:inline;fill:none;fill-opacity:1;stroke:#000000;stroke-width:1.12199998;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
       d="m 35.741778,27.194664 -1.082299,0 0,-8.512001 1.082299,-9e-6 z m -5.563199,-4.274211 a 5.00005,5.000032 0 0 0 9.999999,2e-5 5.00005,5.000032 0 1 0 -9.999999,-2e-5 z"
       inkscape:connector-curvature="0" />

完整的SVG标记可以在小提琴上找到。

您可以使用getBBox()获取<path>的位置:

const centre = knob.node().getBBox();

然后,只需计算其中心即可:

knob.attr("transform", "rotate(" + angle + ", " + 
    (centre.x + centre.width / 2) + ", " + (centre.y + centre.height / 2) + ")");

显然,这里的angle是您想要的角度。

这是一个使用SVG(但更小)的演示,单击SVG中的任意位置以旋转路径:

 let toggle = 0; let svg = d3.select("svg") const knob = d3.select("#switch1") const centre = knob.node().getBBox(); svg.on("click", function() { const angle = (toggle = 1 - toggle) ? 90 : 0; knob.attr("transform", "rotate(" + angle + ", " + (centre.x + centre.width / 2) + ", " + (centre.y + centre.height / 2) + ")"); }) 
 svg { border: 1px solid gray; background-color: lavender; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.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="200" height="100" viewBox="0 0 50 50" id="svg2" version="1.1" inkscape:version="0.91 r13725" sodipodi:docname="bar.svg"> <defs id="defs4" /> <sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="11.2" inkscape:cx="34.921875" inkscape:cy="1047.7595" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" inkscape:window-width="1920" inkscape:window-height="1033" inkscape:window-x="-4" inkscape:window-y="-4" inkscape:window-maximized="1"> <inkscape:grid type="xygrid" id="grid4157" /> </sodipodi:namedview> <metadata id="metadata7"> <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 /> </cc:Work> </rdf:RDF> </metadata> <g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1"> <path id="switch1" style="display:inline;fill:none;fill-opacity:1;stroke:#000000;stroke-width:1.12199998;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" d="m 35.741778,27.194664 -1.082299,0 0,-8.512001 1.082299,-9e-6 zm -5.563199,-4.274211 a 5.00005,5.000032 0 0 0 9.999999,2e-5 5.00005,5.000032 0 1 0 -9.999999,-2e-5 z" inkscape:connector-curvature="0" /> <text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" x="25.714285" y="13.612206" id="text4135" sodipodi:linespacing="125%"><tspan sodipodi:role="line" id="tspan4137" x="25.714285" y="13.612206" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:start;writing-mode:lr-tb;text-anchor:start">OFF</tspan></text> <text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" x="44.566826" y="26.086744" id="text4135-2" sodipodi:linespacing="125%"><tspan sodipodi:role="line" id="tspan4137-2" x="44.566826" y="26.086744" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:start;writing-mode:lr-tb;text-anchor:start">ON</tspan></text> </g> </svg> 

您还可以添加过渡:

 let toggle = 0; let svg = d3.select("svg") const knob = d3.select("#switch1") const centre = knob.node().getBBox(); const centreX = centre.x + centre.width / 2; const centreY = centre.y + centre.height / 2; svg.on("click", function() { const angle = (toggle = 1 - toggle) ? 90 : 0; knob.transition() .ease(d3.easeLinear) .attrTween("transform", function() { return d3.interpolateString("rotate(" + (90 - angle) + ", " + centreX + ", " + centreY + ")", "rotate(" + angle + ", " + centreX + ", " + centreY + ")") }) }) 
 svg { border: 1px solid gray; background-color: lavender; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.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="200" height="100" viewBox="0 0 50 50" id="svg2" version="1.1" inkscape:version="0.91 r13725" sodipodi:docname="bar.svg"> <defs id="defs4" /> <sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="11.2" inkscape:cx="34.921875" inkscape:cy="1047.7595" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" inkscape:window-width="1920" inkscape:window-height="1033" inkscape:window-x="-4" inkscape:window-y="-4" inkscape:window-maximized="1"> <inkscape:grid type="xygrid" id="grid4157" /> </sodipodi:namedview> <metadata id="metadata7"> <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 /> </cc:Work> </rdf:RDF> </metadata> <g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1"> <path id="switch1" style="display:inline;fill:none;fill-opacity:1;stroke:#000000;stroke-width:1.12199998;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" d="m 35.741778,27.194664 -1.082299,0 0,-8.512001 1.082299,-9e-6 zm -5.563199,-4.274211 a 5.00005,5.000032 0 0 0 9.999999,2e-5 5.00005,5.000032 0 1 0 -9.999999,-2e-5 z" inkscape:connector-curvature="0" /> <text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" x="25.714285" y="13.612206" id="text4135" sodipodi:linespacing="125%"><tspan sodipodi:role="line" id="tspan4137" x="25.714285" y="13.612206" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:start;writing-mode:lr-tb;text-anchor:start">OFF</tspan></text> <text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" x="44.566826" y="26.086744" id="text4135-2" sodipodi:linespacing="125%"><tspan sodipodi:role="line" id="tspan4137-2" x="44.566826" y="26.086744" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;line-height:125%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:start;writing-mode:lr-tb;text-anchor:start">ON</tspan></text> </g> </svg> 

尽管Gerardo的答案显示了显而易见的且应用最广泛的解决方案,但还有其他方法可以做到这一点。 这个答案有一些实验性的尝试(Gerardo报告说它在Safari上被破坏了),因为它提出了两种并非现成的方法。 认为它是在探索可能性并增加知识库,而不是呈现惯用方式。


您可以使用transform-origin CSS属性来控制元素转换的原点,而不必获取边界框并做一些公认的简单数学。 因为Firefox似乎对此处理方式不同,所以您还应该设置transform-box:fill-box 然后,将旋转原点设置为50% 50%按最初预期的那样绕其中心旋转元素。 旁注:围绕中心旋转是HTML的默认行为,而SVG默认情况下围绕坐标原点旋转。

这是Gerardo演示的简化版本:

 let toggle = 0; const svg = d3.select("svg") const knob = d3.select("#switch1") svg.on("click", function() { const angle = (toggle = 1 - toggle) ? 90 : 0; knob.attr("transform", "rotate(" + angle + ")"); }) 
 path { fill: none; stroke: #000000; stroke-width: 1.12199998; transform-box: fill-box; transform-origin: 50% 50% } text { font-size: 10px; font-family: Sans; fill: #000000; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script> <svg width="200" height="100" viewBox="0 0 50 50"> <g> <path id="switch1" d="m 35,27 -1,0 0,-9 1,0 zm -5.7,-4 a 5,5 0 0 0 10,0 5,5 0 1 0 -10,0 z" /> <text x="26" y="14">OFF</text> <text x="45" y="26">ON</text> </g> </svg> 

您甚至可以使用hidden-checkbox-label技巧来推送信封,而根本不需要JavaScript!

 path { fill: none; stroke: #000000; stroke-width: 1.12199998; transform-box: fill-box; transform-origin: 50% 50% } text { font-size: 10px; font-family: Sans; fill: #000000; } #dummy { display: none; } #dummy:checked+label path { transform: rotate(90deg); } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script> <input type="checkbox" id="dummy"> <label for="dummy"> <svg width="200" height="100" viewBox="0 0 50 50"> <g> <path id="switch1" d="m 35,27 -1,0 0,-9 1,0 zm -5.7,-4 a 5,5 0 0 0 10,0 5,5 0 1 0 -10,0 z" /> <text x="26" y="14">OFF</text> <text x="45" y="26">ON</text> </g> </svg> </label> 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM