如何正确旋转SVG元素?

7
我一直在尝试创建一个范围为0-100的仪表。我已经在Sketch中创建了这个SVG元素,现在我正在尝试让黑色指针旋转。
为了做到这一点,我已经尝试使用"transform-origin"和"transform: rotate()"来进行调整,但似乎无法像".gif"中那样旋转,因为它总是被切断。我添加了一个JS范围滑块以方便您演示问题。这里还有一个Codepen供您实验。
你能帮我实现.gif中所示的期望结果吗?

enter image description here

$('#percent').on('change', function() {
  $('#needle').css('transform', 'translate(175px, 19px) rotate(' + percentToDegrees($(this).val()) + 'deg)')
})

function percentToDegrees(percent) {
  var degrees = -90;
  var inc = 1.8;
  return degrees += (percent * inc);
}
#needle {
  transform-origin: 0% bottom;
  transform: translate(175px, 19px) rotate(0);
}

input {
  display: block;
  margin: 50px auto;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<svg width="100%" height="177px" viewBox="0 0 385 177" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
        <g id="Artboard" transform="translate(-15.000000, -224.000000)">
            <g id="Group" transform="translate(15.000000, 220.000000)">
                <g id="guage">
                    <path d="M84.8041871,178.856781 L84.8041871,179.169281 L25,179.169281 L25,178.669281 C25,119.519295 57.1931907,67.8894771 105.011512,40.3501901 L135,92.2989954 C105.009619,109.483749 84.8041871,141.810321 84.8041871,178.856781 Z" id="red" fill="#BD3632"></path>
                    <path d="M235.050803,92.4864742 C205.21439,75.1028089 167.169843,73.7652453 135.133157,92.2884751 L134.862916,92.4447251 L105,40.6455806 L105.432385,40.3955806 C156.58355,10.8205878 217.307001,12.8896752 265,40.5376689 L235.050803,92.4864742 L235.050803,92.4864742 Z" id="yellow" fill="#EEAF30"></path>
                    <path d="M235,92.2989954 L264.988488,40.3501901 C312.806809,67.8894771 345,119.519295 345,178.669281 L345,179.169281 L285.195813,179.169281 L285.195813,178.856781 C285.195813,141.810321 264.990381,109.483749 235,92.2989954 L235,92.2989954 Z" id="green" fill="#008542"></path>
                    <text id="100%" font-family="Omnes-Regular, Omnes" font-size="15" font-weight="normal" line-spacing="15" fill="#000000">
                        <tspan x="350" y="180">100%</tspan>
                    </text>
                    <text id="50%" font-family="Omnes-Regular, Omnes" font-size="15" font-weight="normal" fill="#000000">
                        <tspan x="171" y="14">50%</tspan>
                    </text>
                    <text id="0%" font-family="Omnes-Regular, Omnes" font-size="15" font-weight="normal" fill="#000000">
                        <tspan x="0" y="178">0%</tspan>
                    </text>
                </g>
                <g id="needle" transform="translate(175.000000, 19.000000)">
                    <polygon id="Triangle" fill="#3C3C3B" points="10 0 15 162 5 162"></polygon>
                </g>
            </g>
        </g>
    </g>
</svg>

<input type="range" id="percent" value="50" min="0" max="100">


你想实现的是这个吗?链接 - Lal
这里有一个演示链接:点击此处 - Minal Chauhan
相当酷的。 - Divide by Zero
2个回答

7

考虑使用transform-box:fill-box;,然后将原点设置为底部中心,并稍微增加视图框来避免裁剪。我还将旋转移动到多边形上,并保留了g元素的平移。

$('#percent').on('change', function() {
  $('#triangle').css('transform', 'rotate(' + percentToDegrees($(this).val()) + 'deg)')
})

function percentToDegrees(percent) {
  var degrees = -90;
  var inc = 1.8;
  return degrees += (percent * inc);
}
#triangle {
  transform-origin:center bottom;
  transform-box:fill-box;
}

input {
  display: block;
  margin: 50px auto;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<svg width="100%" height="177px" viewBox="0 0 385 185" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
        <g id="Artboard" transform="translate(-15.000000, -224.000000)">
            <g id="Group" transform="translate(15.000000, 220.000000)">
                <g id="guage">
                    <path d="M84.8041871,178.856781 L84.8041871,179.169281 L25,179.169281 L25,178.669281 C25,119.519295 57.1931907,67.8894771 105.011512,40.3501901 L135,92.2989954 C105.009619,109.483749 84.8041871,141.810321 84.8041871,178.856781 Z" id="red" fill="#BD3632"></path>
                    <path d="M235.050803,92.4864742 C205.21439,75.1028089 167.169843,73.7652453 135.133157,92.2884751 L134.862916,92.4447251 L105,40.6455806 L105.432385,40.3955806 C156.58355,10.8205878 217.307001,12.8896752 265,40.5376689 L235.050803,92.4864742 L235.050803,92.4864742 Z" id="yellow" fill="#EEAF30"></path>
                    <path d="M235,92.2989954 L264.988488,40.3501901 C312.806809,67.8894771 345,119.519295 345,178.669281 L345,179.169281 L285.195813,179.169281 L285.195813,178.856781 C285.195813,141.810321 264.990381,109.483749 235,92.2989954 L235,92.2989954 Z" id="green" fill="#008542"></path>
                    <text id="100%" font-family="Omnes-Regular, Omnes" font-size="15" font-weight="normal" line-spacing="15" fill="#000000">
                        <tspan x="350" y="180">100%</tspan>
                    </text>
                    <text id="50%" font-family="Omnes-Regular, Omnes" font-size="15" font-weight="normal" fill="#000000">
                        <tspan x="171" y="14">50%</tspan>
                    </text>
                    <text id="0%" font-family="Omnes-Regular, Omnes" font-size="15" font-weight="normal" fill="#000000">
                        <tspan x="0" y="178">0%</tspan>
                    </text>
                </g>
                <g id="needle" transform="translate(175.000000, 18.000000)">
                    <polygon id="triangle" fill="#3C3C3B" points="10 0 15 162 5 162"></polygon>
                </g>
            </g>
        </g>
    </g>
</svg>

<input type="range" id="percent" value="50" min="0" max="100">


请注意,transform-box仅适用于某些浏览器的最新版本。如果您想要更兼容的解决方案,您可能需要考虑@Kaiido的解决方案,该解决方案在transform-origin中使用绝对坐标。 - Paul LeBeau

5

最简单的方法可能是使用SVG来完成所有操作,只需设置元素的transform属性,而不是它的cssstyle

你只需要设置rotate(angle, origin_x, origin_y) SVG变换方法的第二个和第三个值即可。

$('#percent').on('input', function() {
  $('#needle').attr('transform', 'translate(175, 19) ' +
    'rotate(' + percentToDegrees($(this).val()) + ', 10, 162)')
})

function percentToDegrees(percent) {
  var degrees = -90;
  var inc = 1.8;
  return degrees += (percent * inc);
}
input {
  display: block;
  margin: 50px auto;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<svg width="100%" height="177px" viewBox="0 0 385 177" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
    <g id="Artboard" transform="translate(-15.000000, -224.000000)">
      <g id="Group" transform="translate(15.000000, 220.000000)">
        <g id="guage">
          <path d="M84.8041871,178.856781 L84.8041871,179.169281 L25,179.169281 L25,178.669281 C25,119.519295 57.1931907,67.8894771 105.011512,40.3501901 L135,92.2989954 C105.009619,109.483749 84.8041871,141.810321 84.8041871,178.856781 Z" id="red" fill="#BD3632"></path>
          <path d="M235.050803,92.4864742 C205.21439,75.1028089 167.169843,73.7652453 135.133157,92.2884751 L134.862916,92.4447251 L105,40.6455806 L105.432385,40.3955806 C156.58355,10.8205878 217.307001,12.8896752 265,40.5376689 L235.050803,92.4864742 L235.050803,92.4864742 Z" id="yellow" fill="#EEAF30"></path>
          <path d="M235,92.2989954 L264.988488,40.3501901 C312.806809,67.8894771 345,119.519295 345,178.669281 L345,179.169281 L285.195813,179.169281 L285.195813,178.856781 C285.195813,141.810321 264.990381,109.483749 235,92.2989954 L235,92.2989954 Z" id="green" fill="#008542"></path>
          <text id="100%" font-family="Omnes-Regular, Omnes" font-size="15" font-weight="normal" line-spacing="15" fill="#000000">
            <tspan x="350" y="180">100%</tspan>
          </text>
          <text id="50%" font-family="Omnes-Regular, Omnes" font-size="15" font-weight="normal" fill="#000000">
            <tspan x="171" y="14">50%</tspan>
          </text>
          <text id="0%" font-family="Omnes-Regular, Omnes" font-size="15" font-weight="normal" fill="#000000">
            <tspan x="0" y="178">0%</tspan>
          </text>
        </g>
        <g id="needle" transform="translate(175.000000, 19.000000)">
            <polygon id="Triangle" fill="#3C3C3B" points="10 0 15 162 5 162"></polygon>
        </g>
      </g>
    </g>
  </g>
</svg>

<input type="range" id="percent" value="50" min="0" max="100">

你甚至可以在浏览器兼容性方面获胜 ;-)

请注意,这可以简化为以下内容:

$('#percent').on('input', function() {
  $('#Triangle')
    .attr('transform', 'rotate(' + percentToDegrees($(this).val()) + ', 10, 162)')
})

function percentToDegrees(percent) {
  var degrees = -90;
  var inc = 1.8;
  return degrees += (percent * inc);
}
input {
  display: block;
  margin: 50px auto;
}
#Page-1 text {
  font-family: Omnes-Regular, Omnes;
  font-size: 15px;
  font-weight: normal;
  fill: #000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<svg width="100%" height="177px" viewBox="0 0 385 177" version="1.1">
  <g id="Page-1" stroke="none" fill="none" transform="translate(0, -4)">
    <g id="guage">
      <path d="M84.8041871,178.856781 L84.8041871,179.169281 L25,179.169281 L25,178.669281 C25,119.519295 57.1931907,67.8894771 105.011512,40.3501901 L135,92.2989954 C105.009619,109.483749 84.8041871,141.810321 84.8041871,178.856781 Z" id="red" fill="#BD3632"></path>
      <path d="M235.050803,92.4864742 C205.21439,75.1028089 167.169843,73.7652453 135.133157,92.2884751 L134.862916,92.4447251 L105,40.6455806 L105.432385,40.3955806 C156.58355,10.8205878 217.307001,12.8896752 265,40.5376689 L235.050803,92.4864742 L235.050803,92.4864742 Z" id="yellow" fill="#EEAF30"></path>
      <path d="M235,92.2989954 L264.988488,40.3501901 C312.806809,67.8894771 345,119.519295 345,178.669281 L345,179.169281 L285.195813,179.169281 L285.195813,178.856781 C285.195813,141.810321 264.990381,109.483749 235,92.2989954 L235,92.2989954 Z" id="green" fill="#008542"></path>
      <text id="100%" line-spacing="15">
        <tspan x="350" y="180">100%</tspan>
      </text>
      <text id="50%">
        <tspan x="171" y="14">50%</tspan>
      </text>
      <text id="0%">
        <tspan x="0" y="178">0%</tspan>
      </text>
    </g>
    <g id="needle" transform="translate(175.000000, 19.000000)">
      <polygon id="Triangle" fill="#3C3C3B" points="10 0 15 162 5 162"></polygon>
    </g>
  </g>
</svg>

<input type="range" id="percent" value="50" min="0" max="100">


1
你可以通过执行 $('#Triangle').attr('transform', 'rotate(' + percentToDegrees($(this).val()) + ', 10, 162)'); 来简化事情。 - Paul LeBeau
@PaulLeBeau 当然,OP确实对<g>应用了变换,所以我认为他们希望进行转换,可能还有其他要放在那里的东西。但是您绝对正确,在当前代码中,它过于复杂(像所有这些嵌套的<g>一样)。 - Kaiido
@Kaiido 这只是我的 Sketch 编辑器为我输出的内容。如果您有更简单的标记建议,请随时更新您的答案。 - GBWDev
唯一的问题是指针在0度或180度处被切断。 - GBWDev
@GBWDev 因为这是你的绘图方式。你可能想要 将 viewBox 放大一点 或者改变你的绘图方式,使得即使指针旋转时它们也适合当前的视窗。 - Kaiido

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接