Как создать радиальные линии SVG

Как создать радиальные линии SVGI Я пытаюсь создать шкалу с радиальными линиями и числами в диапазоне 0-100. Вот мой код:

<!DOCTYPE html>
<html>
<meta charset = "UTF-8">
<meta name = "viewport" content = "width=device-width, initial-scale=1.0">

<head>
    <title>SVG Gauge</title>
</head>
<style>
    #wrapper {
        position: relative;  
        margin: auto;
    }

    #meter {
        width: 100%; 
        height: 100%;
        transform: rotateX(180deg);
    }

    .circle {
        fill: none;
    }

    #mask {
        stroke: #404040; 
        stroke-width: 60;
    }

    .blackie {
        fill:none;
        stroke: #000000;
        stroke-width: 30;
    }

    .range { 
        stroke-width: 60; 
    }

    .scale {
        stroke: #cccccc;
    }

    #slider, #lbl {
        position: absolute;
    }

    #slider {
        cursor: pointer;
        left: 0;
        margin: auto;
        right: 0;
        top: 58%;
        width: 94%;
    }

    #lbl {
        background-color: #4B4C51; 
        border-radius: 2px;
        color: white;   
        font-family: 'courier new';
        font-size: 15pt;
        font-weight: bold;
        padding: 4px 4px 2px 4px;
        right: -48px;
        top: 57%;
    }

    #meter_needle {
        height: 40%;
        left: 0;
        margin: auto;
        position: absolute;
        right: 0;
        top: 10%;
        transform-origin: bottom center;
        transform: rotate(270deg);
    }

</style>

<body>
    <div id = "wrapper">
        <svg id = "meter">
            <g class = "scale">
                <defs>
                    <linearGradient id = "grad" x1 = "0%" y1 = "0%" x2 = "100%" y2 = "0%">
                        <stop offset = "0%" style = "stop-color:rgb(102, 102, 255);stop-opacity:1" />
                        <stop offset = "100%" style = "stop-color:rgb(204, 204, 255);stop-opacity:1" />
                    </linearGradient>
                </defs>
                <circle id = "high" class = "circle range" cx = "50%" cy = "50%" stroke = "url(#grad)">
                </circle>
                <circle id = "mask" class = "circle" cx = "50%" cy = "50%">
                </circle>
                <circle id = "low" class = "blackie" cx = "50%" cy = "50%" r = "360">
                </circle>
                <circle id = "outline_ends" class = "circle outline" cx = "50%" cy = "50%">
                </circle>
            </g>
        </svg>
        <img id = "meter_needle" src = "gauge-needle.svg" alt = "">
        <input id = "slider" type = "range" min = "0" max = "100" value = "0" />
        <label id = "lbl" id = "value" for = "">0%</label>
    </div>
    <script>
        var r = 400;
        var circles = document.querySelectorAll('.circle');
        var total_circles = circles.length;
        for (var i = 0; i < total_circles; i++) {
            circles[i].setAttribute('r', r);
        }
        var meter_dimension = (r * 2) + 100;
        var wrapper = document.querySelector('#wrapper');
        wrapper.style.width = meter_dimension + 'px';
        wrapper.style.height = meter_dimension + 'px';

        var cf = 2 * Math.PI * r;
        var semi_cf = cf / 2;
        var z = 40 * Math.PI;

        document.querySelector('#outline_ends')
            .setAttribute('stroke-dasharray', 2 + ',' + (semi_cf - 2));
        document.querySelector('#high')
            .setAttribute('stroke-dasharray', semi_cf + ',' + cf);
        document.querySelector('#mask')
            .setAttribute('stroke-dasharray', semi_cf + ',' + cf);
        document.querySelector('#low')
            .setAttribute('stroke-dasharray', semi_cf - z + ',' + cf);

        var slider = document.querySelector('#slider');
        var lbl = document.querySelector("#lbl");
        var svg = document.querySelector('#meter');
        var high = document.querySelector('#high');
        var mask = document.querySelector('#mask');
        var low = document.querySelector('#low');
        var meter_needle = document.querySelector('#meter_needle');

        function range_change_event() {
            var percent = slider.value;
            var meter_value = semi_cf - ((percent * semi_cf) / 100);
            mask.setAttribute('stroke-dasharray', meter_value + ',' + cf);
            meter_needle.style.transform = 'rotate(' + (270 + ((percent * 180) / 100)) + 'deg)';
            lbl.textContent = percent + '%';
        }
        slider.addEventListener('input', range_change_event);
    </script>
</body>

</html>

Я нашел в сети множество хороших примеров с HTML Canvas и D3js, но ничего, основанного на SVG .. Я думаю создать элемент «линию» и добавить его по черной дуге. Как проще всего создать числовую шкалу?

Создание фильтров для вашего сайта
Создание фильтров для вашего сайта
Фильтры - удобный инструмент в арсенале веб-дизайнера. Они позволяют изменять элементы на странице с помощью всего нескольких строк кода. Эти...
Анимация SVG-узоров без единой строки CSS
Анимация SVG-узоров без единой строки CSS
Недавно я работал над веб-проектом, который позволил мне поэкспериментировать с шаблонами SVG. С SVG очень приятно работать, как только вы получите...
Как использовать d3.js для рисования 2D SVG-элементов в приложении Angular?
Как использовать d3.js для рисования 2D SVG-элементов в приложении Angular?
D3.js - это обширная библиотека, используемая для привязки произвольных данных к объектной модели документа (DOM). Мы разберем основные варианты...
0
0
967
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

What is the simplest way to create the numeric scale?

Самый простой способ анимировать масштабирование круга svg - это анимировать его радиус

<svg version = "1.1" xmlns = "http://www.w3.org/2000/svg" 
    xmlns:xlink = "http://www.w3.org/1999/xlink"
    width = "400" height = "400" viewBox = "0 0 400 400" >  

<circle cx = "200" cy = "200"  r = "10" fill = "none" stroke-width = "2" stroke = "purple" >
<animate attributeName = "r" values = "1;100;1" dur = "4s" repeatCount = "indefinite" />
</circle> 
</svg>	 

Спасибо за пример, но я не спрашиваю о масштабировании SVG. Я хочу сделать числовую шкалу с радиальными линиями по черной внутренней дуге ... как спидометр ... Я пробовал теги svg <line> и <text>, но мне это не нравится, потому что мне нужно найти точные координаты ... Я также пробовали свойство "stroke-dasharray" для создания белых промежутков, но мне это не нравится, потому что белые линии должны быть расширены за пределы дуги.

user10043909 10.09.2018 14:54

@Giannis Tsamandouras Для лучшего понимания проблемы, можете ли вы нарисовать изображение промежуточной и конечной позиции анимации?

Alexandr_TT 10.09.2018 15:18

Это хорошая идея - использовать радиус от круга вместо transform scale. Обязательно попробую использовать!

Bharata 09.02.2019 11:01
Ответ принят как подходящий

Ну вот:

    <svg xmlns = "http://www.w3.org/2000/svg" viewBox = "-250 -250 500 500" width = "500" height = "500" id = "svg">
      <defs>
        <style>
            line {
                stroke: black;
                stroke-width: 1px;
            }

            text {
                fill: red;
                text-anchor: middle;
                font-size: 16px;
                font-family: sans-serif;
            }

            rect {
                fill: transparent;
            }

            #id {
                display: none;
            }

            .origin {
                fill: green;
            }

            .outer {
                fill: none;
                stroke: black;
            }
        </style>
      </defs>

        <circle r = "5" cx = "0" cy = "0" class = "origin"/>
        <path d = "M-180,0 a1,1 0 0,1 360,0" class = "outer"/>

        <g id = "gauge" transform = "rotate(-90)">
            <g id = "noon">
                <rect x = "-10" y = "-220" width = "20" height = "100"/>
                <line x1 = "0" y1 = "-190" x2 = "0" y2 = "-180"/>
                <text x = "0" y = "-200"></text>
            </g>
        </g>

    </svg>

    <script>
        for (i=0; i<=180; i = i + 18) {
            var new_tick = noon.cloneNode(true);
            new_tick.getElementsByTagName('text')[0].textContent = i/180 * 100;
            new_tick.removeAttribute("id");
            new_tick.setAttribute("transform", "rotate(" + i + " 0 0)");
            gauge.appendChild(new_tick);
        }
    </script>

Я думаю, это не требует пояснений. (Например, RECT - это просто руководство, которое вы можете включить, изменив заливку, если хотите лучше визуализировать, что происходит внутри каждого G.)

Дайте мне знать, если у вас возникнут какие-либо вопросы.

Вот Codepen, если это поможет: https://codepen.io/MSCAU/pen/OoQMdV

Я читал эту статью (veerasundar.com/blog/2017/06/…), но ваш ответ - лучшее, что я видел до сих пор. Большое тебе спасибо.

user10043909 10.09.2018 16:35

Рад помочь :)

MSC 10.09.2018 16:58

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