Как правильно повернуть этот элемент SVG?

Я пытался создать датчик с диапазоном от 0 до 100. Я создал этот элемент SVG в Sketch, и теперь я пытаюсь заставить вращение работать для черной иглы.

Чтобы сделать это, я попытался поиграть с transform-origin и transform: rotate(), но я не могу заставить его вращаться, как показано в .gif, так как он всегда кажется обрезанным. Я добавил ползунок диапазона JS для вашего удобства, чтобы продемонстрировать проблему. Здесь также является кодовой ручкой для экспериментов.

Не могли бы вы помочь мне добиться желаемого результата, как показано на гифке?

Как правильно повернуть этот элемент SVG?

$('#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 27.06.2019 13:34

Еще одна демонстрация здесь

Minal Chauhan 27.06.2019 13:39

хотя довольно круто

Spacemoose 27.06.2019 15:17
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Введение в CSS
Введение в CSS
CSS является неотъемлемой частью трех основных составляющих front-end веб-разработки.
Как выровнять Div по центру?
Как выровнять Div по центру?
Чтобы выровнять элемент <div>по горизонтали и вертикали с помощью CSS, можно использовать комбинацию свойств и значений CSS. Вот несколько методов,...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Travel Booking Angular Template один из лучших Travel & Tour booking template in the world. 30+ валидированных HTML5 страниц, которые помогут...
7
3
1 702
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Подумайте transform-box:fill-box;, затем сделайте исходную точку bottom center и немного увеличьте окно просмотра, чтобы избежать разреза. Я также переместил вращение на полигон и сохранил перевод элемента 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 27.06.2019 15:27

Проще всего, вероятно, сделать все это с помощью SVG, просто установив transform атрибут вашего элемента вместо его css style.

Все, что вам нужно, это установить второе и третье значения метода преобразования 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">

Вы можете упростить вещи, просто делая $('#Triangle').attr('transform', 'rotate(' + percentToDegrees($(this).val()) + ', 10, 162)');

Paul LeBeau 27.06.2019 15:24

@PaulLeBeau, конечно, OP применил преобразование к <g>, поэтому я подумал, что они хотели, чтобы оно было преобразовано, может быть, там есть что-то еще. Но вы абсолютно правы в том, что в текущем коде это излишне сложно (как и все эти вложенные <g> кстати).

Kaiido 27.06.2019 15:28

@Kaiido, это то, что выводит для меня мой редактор Sketch. Если у вас есть лучшее предложение по разметке, не стесняйтесь обновить свой ответ чем-то более упрощенным.

GBWDev 28.06.2019 10:03

Единственная проблема в том, что игла обрезается при 0 или 180 градусах.

GBWDev 28.06.2019 10:04

@GBWDev, потому что так сделан твой рисунок. Вы можете захотеть сделать viewBox немного больше или изменить свой рисунок так, чтобы он соответствовал текущему, даже когда стрелка вращается.

Kaiido 28.06.2019 10:10

Другие вопросы по теме