How can I rotate this SVG element correctly?

Consider transform-box:fill-box; then make the origin bottom center and increase the viewbox a little to avoid the cut. I have also moved the rotation to the polygon and kept the translation on the g element.

$('#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">


The easiest is probably to do it all with SVG, simply setting your element's transform attribute instead of its css style.

All you need is to set the second and third values of the rotate(angle, origin_x, origin_y) SVG transform method.

$('#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">

You'll even win in browser compat ;-)

And note that this could be all simplified to:

$('#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">

Tags:

Html

Css

Svg