Как нарисовать сектор круга в CSS?

Что ж, нарисовать круг с помощью чистого CSS несложно.

.circle {
    width: 100px;
    height: 100px;
    border-radius: 100px;
    border: 3px solid black;
    background-color: green;
}

Как нарисовать сектор? Учитывая степень X [0-360], я хочу нарисовать сектор X градусов. Могу ли я сделать это с помощью чистого CSS?

Например:

введите здесь описание изображения

Спасибо + Пример

Спасибо Джонатан, я использовал первый метод. Если это кому-то поможет, вот пример функции JQuery, которая получает процент и рисует сектор. Сектор находится за процентным кругом, и этот пример показывает, как получить дугу вокруг круга из начального градуса.

$(function drawSector() {
  var activeBorder = $("#activeBorder");
  var prec = activeBorder.children().children().text();
  if (prec > 100)
    prec = 100;
  var deg = prec * 3.6;
  if (deg <= 180) {
    activeBorder.css('background-image', 'linear-gradient(' + (90 + deg) + 'deg, transparent 50%, #A2ECFB 50%),linear-gradient(90deg, #A2ECFB 50%, transparent 50%)');
  } else {
    activeBorder.css('background-image', 'linear-gradient(' + (deg - 90) + 'deg, transparent 50%, #39B4CC 50%),linear-gradient(90deg, #A2ECFB 50%, transparent 50%)');
  }

  var startDeg = $("#startDeg").attr("class");
  activeBorder.css('transform', 'rotate(' + startDeg + 'deg)');
  $("#circle").css('transform', 'rotate(' + (-startDeg) + 'deg)');
});
.container {
  width: 110px;
  height: 110px;
  margin: 100px auto;
}

.prec {
  top: 30px;
  position: relative;
  font-size: 30px;
}

.prec:after {
  content: '%';
}

.circle {
  position: relative;
  top: 5px;
  left: 5px;
  text-align: center;
  width: 100px;
  height: 100px;
  border-radius: 100%;
  background-color: #E6F4F7;
}

.active-border {
  position: relative;
  text-align: center;
  width: 110px;
  height: 110px;
  border-radius: 100%;
  background-color: #39B4CC;
  background-image: linear-gradient(91deg, transparent 50%, #A2ECFB 50%), linear-gradient(90deg, #A2ECFB 50%, transparent 50%);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>

<div class="container">
  <div id="activeBorder" class="active-border">
    <div id="circle" class="circle">
      <span class="prec">66</span>
      <span id="startDeg" class="90"></span>
    </div>
  </div>
</div>

демонстрация JSFiddle

$(function drawSector() {
    // Get degrees
    ...
    // Draw a sector
    if (deg <= 180) {
        activeBorder.css('background-image', 'linear-gradient(' + (90+deg) + 'deg, transparent 50%, #A2ECFB 50%), linear-gradient(90deg, #A2ECFB 50%, transparent 50%)');
    }
    else {
        activeBorder.css('background-image', 'linear-gradient(' + (deg-90) + 'deg, transparent 50%, #39B4CC 50%), linear-gradient(90deg, #A2ECFB 50%, transparent 50%)');
    }

    // Rotate to meet the start degree
    activeBorder.css('transform','rotate(' + startDeg + 'deg)');
});

person Itay Gal    schedule 18.01.2014    source источник


Ответы (13)


CSS и множественные фоновые градиенты

Вместо того, чтобы пытаться рисовать зеленую часть, вы можете вместо этого нарисовать белые части:

pie {
    border-radius: 50%;
    background-color: green;
}

.ten {
    background-image:
        /* 10% = 126deg = 90 + ( 360 * .1 ) */
        linear-gradient(126deg, transparent 50%, white 50%),
        linear-gradient(90deg, white 50%, transparent 50%);
}

pie {
  width: 5em;
  height: 5em;
  display: block;
  border-radius: 50%;
  background-color: green;
  border: 2px solid green;
  float: left;
  margin: 1em;
}

.ten {
  background-image: linear-gradient(126deg, transparent 50%, white 50%), linear-gradient(90deg, white 50%, transparent 50%);
}

.twentyfive {
  background-image: linear-gradient(180deg, transparent 50%, white 50%), linear-gradient(90deg, white 50%, transparent 50%);
}

.fifty {
  background-image: linear-gradient(90deg, white 50%, transparent 50%);
}


/* Slices greater than 50% require first gradient
   to be transparent -> green */

.seventyfive {
  background-image: linear-gradient(180deg, transparent 50%, green 50%), linear-gradient(90deg, white 50%, transparent 50%);
}

.onehundred {
  background-image: none;
}
<pie class="ten"></pie>
<pie class="twentyfive"></pie>
<pie class="fifty"></pie>
<pie class="seventyfive"></pie>
<pie class="onehundred"></pie>

Демонстрация: http://jsfiddle.net/jonathansampson/7PtEm/

введите здесь описание изображения

Масштабируемая векторная графика

Если есть возможность, вы можете добиться аналогичного эффекта, используя элементы SVG <circle> и <path>. Рассмотрим следующее:

<svg>
  <circle cx="115" cy="115" r="110"></circle>
  <path d="M115,115 L115,5 A110,110 1 0,1 190,35 z"></path>
</svg>

Вышеизложенное довольно прямолинейно. У нас есть элемент, содержащий круг и путь. Центр круга имеет размер 115x115 (что делает элемент SVG размером 230x230). Круг имеет радиус 110, что делает его в общей сложности 220 шириной (оставляя границу 10).

Затем мы добавляем элемент <path>, что является самой сложной частью этого примера. Этот элемент имеет один атрибут, который определяет, где и как будет отрисовываться путь. Он начинается со следующего значения:

M115,115

Это указывает, что путь должен начинаться в центре вышеупомянутого круга. Затем мы проводим линию от этого места к следующему местоположению:

L115,5

Это рисует вертикальную линию от центра круга до вершины элемента (ну, пять пикселей сверху). Именно в этот момент все становится немного сложнее, но все еще очень понятно.

Теперь мы рисуем дугу из нашего текущего местоположения (115,5):

A110,110 1 0,1 190,35 z

Это создаст нашу дугу и придаст ей радиус, соответствующий радиусу нашей окружности (110). Два значения представляют x-радиус и y-радиус, и оба равны, так как мы имеем дело с кругом. Следующий набор важных чисел — последний, 190,35. Это говорит дуге, где завершить.

Что касается остальной информации (1 0,1 и z), они управляют кривизной, направлением и концом самой дуги. Вы можете узнать о них больше, ознакомившись с любым онлайн-справочником по пути SVG.

Чтобы получить срез другого размера, просто измените 190,35, чтобы отразить больший или меньший набор координат. Вы можете обнаружить, что вам нужно создать вторую дугу, если вы хотите охватить более 180 градусов.

Если вы хотите определить координаты x и y по углу, вы можете использовать следующие уравнения:

x = cx + r * cos(a)
y = cy + r * sin(a)

В приведенном выше примере степень 76 будет:

x = 115 + 110 * cos(76)
y = 115 + 110 * sin(76)

Что дает нам 205.676,177.272.

С некоторой легкостью вы можете создать следующее:

circle {
  fill: #f1f1f1;
  stroke: green;
  stroke-width: 5;
}

path {
  fill: green;
}

svg.pie {
  width: 230px;
  height: 230px;
}
<svg class="pie">
  <circle cx="115" cy="115" r="110"></circle>
  <path d="M115,115 L115,5 A110,110 1 0,1 190,35 z"></path>
</svg>

<svg class="pie">
  <circle cx="115" cy="115" r="110"></circle>
  <path d="M115,115 L115,5 A110,110 1 0,1 225,115 z"></path>
</svg>

<svg class="pie">
  <circle cx="115" cy="115" r="110"></circle>
  <path d="M115,115 L115,5 A110,110 1 0,1 115,225 A110,110 1 0,1 35,190 z"></path>
</svg>

Демонстрация: http://jsfiddle.net/jonathansampson/tYaVW/

введите здесь описание изображения

person Sampson    schedule 18.01.2014
comment
Отличный ответ! Очень тщательно. Следует отметить, что если вы хотите иметь прозрачный фон для неиспользуемой части круговой диаграммы, то вы должны использовать метод SVG. - person Neil Monroe; 06.01.2015
comment
@NeilMonroe Это правильно, хотя некоторые из круговых схем можно было бы сделать прозрачным цветом, таким образом раскрывая содержимое круга. - person Sampson; 06.01.2015
comment
@JonathanSampson, это мне очень помогло... жаль, что я не могу проголосовать еще 10 раз. Спасибо :) - person Hiral; 20.02.2015
comment
Вот совет: добавьте некоторое преобразование pie { transform: rotate(-90deg) }, чтобы упростить вычисления. - person Endless; 23.09.2016
comment
CSS-решение отличное. Я использую его в своем плагине jQuery: github.com/jorunkel/jquery.article-progress (см. живую демонстрацию) - person jor; 08.08.2017
comment
Разве это не должно быть cos (76 * pi / 180) и sin (76 * pi / 180)? 76 градусов - это следующее, и вы должны начать с правой стороны: 141.611408516,221.7325298904 dropbox.com/s/l9450gji5424hp9/ - person Intellix; 11.02.2018
comment
Не уверен, что я делал что-то не так, но я не получал правильные размеры кусочков пирога, используя формулу, приведенную в этом ответе. Вместо этого я сделал ((360 * 0,85) - 90) для значений более 50% [где 0,85 = 85%] и ((360 * 0,35) + 90) для значений ниже 50% [где 0,35 равно 35%]. Это в дополнение к изменению прозрачного/зеленого порядка линейного градиента. Теперь он дает точные срезы. Тем не менее, отличный ответ и очень помог мне! - person Tom; 02.09.2020
comment
@Sampson, не могли бы вы помочь мне, как отобразить текст внутри каждого сектора? - person user9437856; 19.09.2020
comment
Это круто - person mvinayakam; 25.10.2020

Это вполне возможно с использованием свойств overflow и transform без каких-либо сложных вычислений.

> Повернуть трансформировать

Для углов менее 180 градусов

  1. Добавьте элемент с соотношением сторон 2:1 и overflow: hidden;

  2. Добавьте псевдоэлемент с радиусом верхней границы, равным высоте элемента, и радиусом нижней границы, равным 0.

  3. Поместите transform-origin: 50% 100%; Это трансформирует псевдоэлемент из его средней нижней части.

  4. Преобразование: повернуть(); псевдоэлемент добавлением требуемого угла,
    т.е.., transform: rotate(180 - rqrd. angle);

Посмотри, как это работает :

введите здесь описание изображения

Например:
Сектор 40 градусов, использующий этот метод: Fiddle< /сильный>

div {
  ...
  overflow: hidden;
  ...
}
div:before {
  ...
  border-radius: 100px 100px 0 0;
  transform-origin: 50% 100%;
  transform: rotate(140deg);
  ...
}

div {
  height: 100px;
  width: 200px;
  overflow: hidden;
  position: relative;
}
div:before {
  height: inherit;
  width: inherit;
  position: absolute;
  content: "";
  border-radius: 100px 100px 0 0;
  background-color: crimson;
  -webkit-transform-origin: 50% 100%;
  -moz-transform-origin: 50% 100%;
  -ms-transform-origin: 50% 100%;
  transform-origin: 50% 100%;
  -webkit-transform: rotate(140deg);
  -moz-transform: rotate(140deg);
  -ms-transform: rotate(140deg);
  transform: rotate(140deg);
}
<div></div>

> Наклонное преобразование

Вы также можете поместить изображение внутрь сектора!

Это можно сделать с помощью преобразований skew для родителя и наклона -ve для псевдоэлемента:
Fiddle< /сильный>

div {
    ...
    overflow: hidden;
    transform-origin: 0% 100%;
    transform: skew(-50deg);  /*Complement of rqrd angle*/
    ...
}
div:before {
    ...
    transform-origin: 0% 100%;
    transform: skew(50deg);
    ...
}

Посмотрите, как это работает:

введите здесь описание изображения

div {
  height: 200px;
  width: 200px;
  overflow: hidden;
  -webkit-transform-origin: 0% 100%;
  -moz-transform-origin: 0% 100%;
  -ms-transform-origin: 0% 100%;
  transform-origin: 0% 100%;
  -webkit-transform: skew(-50deg);
  -moz-transform: skew(-50deg);
  -ms-transform: skew(-50deg);
  transform: skew(-50deg); /*Complement of rqrd angle or (90 - angle)*/
  position: relative;
}
div:before {
  height: inherit;
  width: inherit;
  position: absolute;
  content: "";
  border-radius: 0 200px 0 0;
  background: url('http://www.placekitten.com/g/300/200/');
  -webkit-transform-origin: 0% 100%;
  -moz-transform-origin: 0% 100%;
  -ms-transform-origin: 0% 100%;
  transform-origin: 0% 100%;
  -webkit-transform: skew(50deg);
  -moz-transform: skew(50deg);
  -ms-transform: skew(50deg);
  transform: skew(50deg);
}
<div></div>


Благодарности: я не хочу быть самозванцем, я использовал идеи, которые я ранее использовал здесь и здесь.

person The Pragmatick    schedule 28.02.2015
comment
GIF очень хороший, не могли бы вы рассказать мне, как вы сделали такой GIF? - person James; 12.01.2021

Это помогает?

.circle {
  width: 16em;
  height: 16em;
  border-radius: 50%;
  background: linear-gradient(36deg, #272b66 42.34%, transparent 42.34%) 0 0;
  background-repeat: no-repeat;
  background-size: 50% 50%;
}
<div class="circle"></div>

Рабочая скрипта

На самом деле здесь необходим некоторый геометрический расчет. Но позвольте мне объяснить это вкратце:

Учитывая 4 четверти круга, можно вычислить угол линейного градиента в каждой четверти. И background-position определяет квартал:

Q I   =>  100% 0
Q II  =>  100% 100%
Q III =>  0    100%
Q IV  =>  0    0

Единственное, что осталось, это откуда взялась использованная color-stop:

Рассмотрим 30-угольный кусок круга в 1-й четверти.

Как объяснила талантливая Ана Тюдор в своем отличная статья. Если мы возьмем длину ширины квадрата равной a, то длина половины диагонали будет равна a*sqrt(2)/2.

Если мы возьмем степень градиента равной g, разница между двумя углами градиента и диагонали будет равна d, тогда длину color-stop можно рассчитать по формуле:

a*sin(g) / (a*sqrt(2)/2 * cos(d))
= sin(g) / (sqrt(2)  /2 * cos(d)) 

Итак, в этом случае у нас есть sin(30deg) / (sqrt(2)*cos((45-30)deg)) = 0.3660, а значение% для цветовой остановки равно 36.60%.

Поскольку наша фигура находится в 1-й четверти, background-position равно 100% 0.

и линейный градиент будет таким образом:

linear-gradient(-30deg, orange 36.60%, transparent 36.60%) 100% 0;

.circle {
  width: 16em;
  height: 16em;
  border-radius: 50%;
  background: linear-gradient(-30deg, orange 36.60%, transparent 36.60%) 100% 0;
  background-repeat: no-repeat;
  background-size: 50% 50%;
}
<div class="circle"></div>

Я рекомендую прочитать статью Аны для более подробной информации.

person Hashem Qolami    schedule 18.01.2014
comment
Я не уверен, что понимаю решение. Что делать, если я хочу установить градусы на 236? Если я изменю значение 36 градусов на 236 градусов, это не даст ожидаемого результата. - person Itay Gal; 18.01.2014
comment
@ItayGal Возможно, вы захотите прочитать этот блестящий пост Аны Тюдор. - person Lars Beck; 18.01.2014
comment
Когда я пытаюсь использовать это уравнение для 120 градусов, оно не работает. Не могли бы вы привести пример уравнения для 120 градусов, пожалуйста? - person grvpanchal; 28.11.2014
comment
хотя я не использую это в своей реальной работе, но математика фантастическая.... - person James; 18.01.2021

  1. Вам нужно нарисовать круг
  2. используйте clip-path, чтобы вырезать сектор (вам нужно немного посчитать)

вы можете поиграть с clip-path здесь

вот демо:

#skills {
  position: relative;
  width: 300px;
  height: 300px;
  margin: 30px auto;
}

.circle {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  position: absolute;
}

.animate {
  -webkit-transition: 0.2s cubic-bezier(.74,1.13,.83,1.2);
  -moz-transition: 0.2s cubic-bezier(.74,1.13,.83,1.2);
  -o-transition: 0.2s cubic-bezier(.74,1.13,.83,1.2);
  transition: 0.2s cubic-bezier(.74,1.13,.83,1.2);
}

.animate:hover {
  transform: scale(1.1);
  transform-origin: center center;
}

#part1 {
  background-color: #E64C65;
  -webkit-clip-path: polygon(50% 0, 50% 50%, 100% 41.2%, 100% 0);
  clip-path: polygon(50% 0, 50% 50%, 100% 41.2%, 100% 0);
}

#part2 {
  background-color: #11A8AB;
  -webkit-clip-path: polygon(50% 50%, 100% 41.2%, 100% 100%, 63.4% 100%);
  clip-path: polygon(50% 50%, 100% 41.2%, 100% 100%, 63.4% 100%);
}

#part3 {
  background-color: #4FC4F6;
  -webkit-clip-path: polygon(50% 50%, 36.6% 100%, 63.4% 100%);
  clip-path: polygon(50% 50%, 36.6% 100%, 63.4% 100%);
}

#part4 {
  background-color: #FFED0D;
  -webkit-clip-path: polygon(50% 50%, 0 100%, 36.6% 100%);
  clip-path: polygon(50% 50%, 0 100%, 36.6% 100%);
}

#part5 {
  background-color: #F46FDA;
  -webkit-clip-path: polygon(50% 50%, 0 36.6%, 0 100%);
  clip-path: polygon(50% 50%, 0 36.6%, 0 100%);
}

#part6 {
  background-color: #15BFCC;
  -webkit-clip-path: polygon(50% 50%, 0 36.6%, 0 0, 50% 0);
  clip-path: polygon(50% 50%, 0 36.6%, 0 0, 50% 0);
}
<div id="skills">
  <div id="part1" class="circle animate"></div>
  <div id="part2" class="circle animate"></div>
  <div id="part3" class="circle animate"></div>
  <div id="part4" class="circle animate"></div>
  <div id="part5" class="circle animate"></div>
  <div id="part6" class="circle animate"></div>
</div>

person Gavin    schedule 23.07.2015
comment
работает хром, но не работает браузер firefox и другой браузер. дать любую идею - person karthi; 27.07.2016
comment
@karthi Firefox поддерживает clip-path только с путем, определенным в SVG. Таким образом, вы можете использовать SVG в качестве обходного пути. В то время как для IE я не знаю лучшего решения, кроме изображений. - person Gavin; 01.08.2016
comment
можете ли вы привести пример SVG .. я не знаю, как изменить ваш код в SVG - person karthi; 01.08.2016
comment
@karthi Сейчас у меня нет под рукой примера, но вы можете проверить stackoverflow.com/questions/33816793/ для примера - person Gavin; 03.08.2016

так как я вообще не нашел удовлетворительного ответа, мне пришлось опуститься на колени, используя функцию clip-path и целое воскресенье css, чтобы наконец получить то, что я хотел.

вы можете выбрать начальный и конечный угол, и тогда элемент будет красиво рисовать только это, ничего больше. вам понадобится только решение радиуса границы для рисования базового круга.

мои решения работают с сеткой из четырех полигонов, каждый из которых обеспечивает возможную начальную или конечную точку для значений 0-90 ° соответственно. 0-100%, 90-180° соотв. 0-100% и т. д., общая центральная точка и, следовательно, есть два раза по 4 сегмента. вы можете представить себе механику как телескопический стержень с несколькими сегментами, каждый из которых выполняет свою сегментированную работу от 0 до N благодаря механике, сохраняя при этом некоторую ясность в коде (0-90,90-180 ..), т.е. пришлось вручную повернуть (-45 градусов) div, чтобы 0 ° == 12 ''.

вот небольшой набросок, который может проиллюстрировать, как я это сделал:

схема

обратите внимание, что вы не можете использовать это в каких-либо коммерческих целях, поскольку я не нашел подобного решения в Интернете, следовательно, в этом должна быть какая-то ценность. Пожалуйста, уважайте это.


рисование сегментов круга с помощью css von c. schaefer ist lizenziert unter Creative Commons Namensnennung - Nicht kommerziell - Keine Bearbeitungen 4.0 International Lizenz.

            <script src="http://code.jquery.com/jquery-latest.js"></script>

<style type="text/css">
    .circle{
        position: absolute;
        top: 100px;

        width: 600px;
        height: 600px;
        border-radius: 50%;
        background-color: #FFFF00;
        opacity: .9;

        -webkit-transform: rotate(45deg);

}

<script type="text/javaScript">

    var obj;
    var start, end;
    function rangeStart(val) {
        obj =  $("body").find(".circle");
        start = val;
        setAngle(obj, start, end);
    }

    function rangeEnd(val) {
        obj =  $("body").find(".circle");
        end = val;
        setAngle(obj, start, end);
    }

    function applyMasking(obj) {
        obj.css("-webkit-clip-path", ptsToString());
    }

    // not working for degree start to be lower than end, hence, we set the interface to automatically adapt to that exception:
    /*
    function checkForRangeExceptions() {
        if(end < start) {
            $("body").find("input[name='rangeLower']").val($("body").find("input[name='rangeUpper']").val());
            $("body").find("input[name='rangeLower']").slider('refresh');
        }
    }
    */

    // setInterval(doit, 200);

    var angie = 0;
    function doit() {
        obj =  $("body").find(".circle");
        if(angie < 360)
            angie+=15;
        else angie = 0;
        setAngle(obj, 0, angie);
    }


    function ptsToString() {
        var str = "";
        str+="polygon(";
        for(var i=0; i < pts.length; i++) {
            str+=pts[i].x+"% ";
            if(i != pts.length-1)
                str+=pts[i].y+"% ,";
            else str+=pts[i].y+"%";
        }
        str+=")";
        return str;
    }

    /*
    gets passed an html element and sets its clip-path according to the passed angle,
    starting at 0°; note that from a clock perspective, we start at +45° and hence have 
    to add that value to passed angles later on:
    */
    var pts = 
    [
     {x: 50, y: 50}, {x: 0, y: 0}, {x: 0, y: 0},
     {x: 0, y: 0}, {x: 0, y: 0}, {x: 0, y: 0},
     {x: 0, y: 0}, {x: 0, y: 0}, {x: 0, y: 0}
    ];
    var lb, ub;
    var sa, ea;
    function setAngle(obj, start, end) {
        // if no start, set 0° as default:
        start = (start == undefined ? start = 0 : start);

        // find out upper and lower sector bounds: 
        lb = (angleToSector(start) * 2) - 1;
        ub = angleToSector(end) * 2;

        // find start end end angles:
        sa = mapAngleToPoint(start);
        ea = mapAngleToPoint(end); 

        // now set points except start point which is 0:
        for(var i=1; i < pts.length; i++) {

            // set all below lb to lb:
            if(i <= lb) { pts[i].x = sa.x; pts[i].y = sa.y; }

            // set all in between to max values:
            else if(i > lb && i < ub) {
                pts[i] = setMax(i);
            }

            // set all above ub to ub:
            else if(i >= ub) { pts[i].x = ea.x; pts[i].y = ea.y; }

        }

        // apply masking:
        applyMasking(obj);

    }

    // assuming that 100 need to map 90°:
    function angleToPerc(angle) {
        return angle * (100/90);
    }

    function lowerBound(angle) {
        return (mapAngleToSector(angle));
    }

    function uppperBound(angle){
        return (mapAngleToSector(angle));           
    }

    // sectors 1-4
    function angleToSector(angle) {
            if      (angle >= 0   && angle < 90)  return 1;
            else if (angle >= 90  && angle < 180) return 2;
            else if (angle >= 180 && angle < 270) return 3;
            else if (angle >= 270 && angle <= 360) return 4;
    }

    // this maps the passed angle to a coordinate value:
    var as;
    function mapAngleToPoint(angle) {
            var pt = {x: 0, y: 0};
            as = angleToSector(angle);
            if(as == 1)       {pt.x = angleToPerc(angle); pt.y = 0; }
            else if(as == 2)  {pt.x = 100; pt.y = angleToPerc(angle-90)}
            else if(as == 3)  {pt.x = 100-angleToPerc(angle-180); pt.y = 100; }
            else if(as == 4)  {pt.x = 0; pt.y = 100-angleToPerc(angle-270); }
            return pt;
    }

    // set a point to its max by index:
    function setMax(index) {
        var pt = {x: 0, y: 0};
        if      (index == 1 || index == 2) { pt.x = 100; pt.y = 0; }
        else if (index == 3 || index == 4) { pt.x = 100; pt.y = 100; }
        else if (index == 5 || index == 6) { pt.x = 0; pt.y = 100; }
        else if (index == 7 || index == 8) { pt.x = 0; pt.y = 0; }
        return pt;
    }

</script>

</head>

<body>

    <div class="circle">

    </div>

    <input type="range" name="rangeLower" value="0" min="0" max="360" onchange="rangeStart(this.value);">
    <input type="range" name="rangeUpper" value="66"min="0" max="360" onchange="rangeEnd(this.value);">


</body>

person c. schaefer    schedule 07.06.2015

У меня есть другое решение.

#pie {
  position: relative;
  width: 100px;
  height: 100px;
  background-color: #76dd76;
  border-radius: 50%;
  border: 1px solid #76dd76;
}

#pie:before,
#pie:after {
  position: absolute;
  content: "";
  display: block;
  width: 50%;
  height: 50%;
  -webkit-transform-origin: right bottom;
  -moz-transform-origin: right bottom;
  -ms-transform-origin: right bottom;
  transform-origin: right bottom;
  background-color: white;
  border-top-left-radius: 100%;
}

#pie:after {
  -webkit-transform: rotate(45deg);
  -moz-transform: rotate(45deg);
  -ms-transform: rotate(45deg);
  transform: rotate(45deg);
}
<div id="pie"></div>

ДЕМО: http://jsfiddle.net/F6qz9/

person Nolan    schedule 21.01.2014
comment
Это будет работать для половины пирога. Если вам нужен полный диапазон, вы можете воспользоваться этой техникой и добавить диапазон в элемент круговой диаграммы для еще двух стилей псевдоэлементов. - person Neil Monroe; 05.01.2015

Посмотрите это, чтобы получить представление о том, как решить вашу проблему.

<div class="circle"></div>

.circle{
    width: 100px;
    height: 100px;
    background-color: green;
    border-radius: 100px;
    position: relative;
}

.circle:before,
.circle:after {
    border: 50px solid white;
    border-color: transparent transparent white white;
    border-radius: 100px;
    content: '';
    height: 0;
    position: absolute;
    top: 0;
    left: 0;
    width: 0;
    /* this is to have it white from 180 to 360 degrees on the left side */
    transform:rotate(45deg);
    -ms-transform:rotate(45deg); /* IE 9 */
    -webkit-transform:rotate(45deg); /* Safari and Chrome */
}

/* the green sector is now 180 minus 45 plus 0 degree */
.circle:after {
    transform:rotate(0deg);
    -ms-transform:rotate(0deg); /* IE 9 */
    -webkit-transform:rotate(0deg); /* Safari and Chrome */
}

/* the green sector is now 180 minus 45 plus -75 degree */
/*.circle:after {
    transform:rotate(-75deg);
    -ms-transform:rotate(-75deg);
    -webkit-transform:rotate(-75deg);
}*/

Демо

person MichaB    schedule 18.01.2014
comment
Хороший трюк, дружище! Но одно но - вы не можете создавать прозрачные сектора с углом ‹ 45 ;) Вы можете создавать скрытые сектора. - person The Pragmatick; 28.02.2015

Все ответы здесь творческие. Удивительно, как люди решают одну и ту же проблему разными способами. Принятый ответ Сэмпсона действительно классный, но я не знаю, почему он решил нарисовать белую часть вместо зеленой, поэтому я подумал о том, чтобы поделиться модифицированной версией, которая на самом деле рисует зеленый цвет. Я просто нахожу это немного более простым, поэтому я делюсь им на случай, если другие сочтут его полезным.

pie {
    width: 5em;
    height: 5em;
    display: block;
    border-radius: 50%;
    border: 2px solid green;
    float: left;
    margin: 1em;
}

.ten {
    background-image:
      linear-gradient(-54deg, white 50%, transparent 50%),
      linear-gradient(-90deg, green 50%, transparent 50%);
}

.twentyfive {
    background-image:
      linear-gradient(0deg, white 50%, transparent 50%),
      linear-gradient(-90deg, green 50%, transparent 50%);
}

.fifty {
    background-image:
      linear-gradient(-90deg, green 50%, transparent 50%);
}

/* Slices greater than 50% require first gradient to be green -> transparent */

.seventyfive {
    background-image:
      linear-gradient(0deg, green 50%, transparent 50%),
      linear-gradient(-90deg, green 50%, transparent 50%);
}

.onehundred {
    background-color: green;
}
<pie class="ten"></pie>
<pie class="twentyfive"></pie>
<pie class="fifty"></pie>
<pie class="seventyfive"></pie>
<pie class="onehundred"></pie>

person Racil Hilan    schedule 30.09.2015

Поскольку мне это нужно было динамически, вот небольшой плагин jQuery. например вызовите $('selector').pieChart(0.4, 'white' 'green'), чтобы показать 40-процентный зеленый сегмент на белом круге.

// LIBRARY FUNCTION
$.fn.pieChart = function(proportion, bg, fg) {
  var angle, grads;
  angle = Math.round(360 * (proportion % 0.5) - 90);
  grads = [
    "linear-gradient(" + angle + "deg, " + (proportion < 0.5 ? bg : fg) + " 50%, transparent 50% )",
    "linear-gradient(-90deg, " + fg + " 50%, transparent 50%)"
  ];
  return $(this).css({
    'background-color': proportion==1 ? fg : bg,
    'background-image': grads.join(','),
    'border': '1px solid '+fg
  });
};

// DEMO
for (var i=0; i <= 10; i++) {
  $('<div class="pie" />').appendTo('body').pieChart(i/10, 'white', 'green');
}
.pie {
  display: inline-block;
  margin: 10px;
  border-radius: 50%;
  width: 100px;
  height: 100px;
}
<script src="https://code.jquery.com/jquery-3.0.0.js"></script>

Это основано на примере Racil здесь. (Обратите внимание, что я не мог использовать плагин OP в отредактированном ответе, поскольку он не работает для секторов, охватывающих более 180 градусов.)

person mahemoff    schedule 18.03.2017
comment
+1 за упоминание моего имени :). Нет, +1 за преобразование в крутую функцию. Может быть, вам стоит создать из него библиотеку ;). - person Racil Hilan; 13.12.2017

Вы можете использовать круг с пунктирной линией.

<svg viewBox="-8 -8 16 16">
  <circle
    cx="0"
    cy="0"
    r="4"
    transform="rotate(270)"
    stroke-width="8"
    stroke-dasharray="4, 26"
    stroke="green"
    fill="none"
  />
</svg>
  • Сделайте линию вдвое толще радиуса круга, чтобы она доходила до центра круга.
  • Поиграйте со значением stroke-dasharray, чтобы определить, насколько большой размер круговой диаграммы вы хотите видеть.

Бонус: Преимущество использования круга вместо пути заключается в том, что вы можете легко анимировать его при изменении размера круга: просто добавьте что-то вроде transition: stroke-dasharray .5s; в css круга.

person Karine Larouche    schedule 27.07.2019

У меня немного другой подход, который можно легко анимировать без использования SVG.

Он использует очень специфические ширину, высоту и ширину границ, а также прямоугольное отсечение, поэтому с ними нужно обращаться осторожно, когда вам нужно изменить размеры. Здесь важно отметить, что если вы хотите изменить круговую диаграмму, вам необходимо обновить все значения em ПРОПОРЦИОНАЛЬНО, т. е. все должны быть масштабированы одним и тем же коэффициентом.

Обратите внимание, что полный полукруг необходимо добавить, если круговая диаграмма заполнена более чем на 50% (> 180 градусов окрашены). Эта часть должна обрабатываться динамически в JS, если вы ее анимируете.

<style>
.timer {
    position: relative;
    width: 4em;
    height: 4em;
    float: left;
    margin: 1px 30px 0 0;
}


.timer > #slice {
    position: absolute;
    width: 4em;
    height: 4em;
    clip: rect(0px, 4em, 4em, 2em);
}

.timer > #slice.gt50 {
    clip: rect(auto, auto, auto, auto);
}

.timer > #slice > .pie {
    border: 3.2em solid green;
    position: absolute;
    width: 3.8em;
    height: 3.8em;
    clip: rect(0em, 2em, 4em, 0em);
    -moz-border-radius: 2em;
    -webkit-border-radius: 2em;
    border-radius: 2em;
}

.timer > #slice > .pie.fill {
    -moz-transform: rotate(180deg) !important;
    -webkit-transform: rotate(180deg) !important;
    -o-transform: rotate(180deg) !important;
    transform: rotate(180deg) !important;
}

.timer.fill > #slice > .pie {
    border: transparent;
    background-color: green;
    width: 4em;
    height: 4em;
}
</style>    
<div class="timer fill">
</div>
<script>
const PIE_INTERVAL_TIME = 1000; // one second interval time
const PERCENT_INTERVAL = 1.67; // 100 / 60 seconds
const stopInterval = setInterval(pieInterval(), PIE_INTERVAL_TIME);

function pieInterval() {
    let percent = 0;
    return function() {
        percent += PERCENT_INTERVAL;
            const timer = $('.timer');
            const gt50 = percent > 50 ? 'gt50' : '';
            const pieFill = percent > 50 ? '<div class="pie fill"></div>' : '';
      let deg = (360/100) * percent;
      timer.html(
        `<div id="slice" class="${gt50}">
            <div class="pie"></div>
            ${pieFill}
        </div>`);

      if (percent >= 100) {
        deg = 360;
        clearInterval(stopInterval);
      }

      $('#slice').find('.pie').css({
        '-moz-transform':'rotate('+deg+'deg)',
        '-webkit-transform':'rotate('+deg+'deg)',
        '-o-transform':'rotate('+deg+'deg)',
        'transform':'rotate('+deg+'deg)'
       });
    };
}
</script>

Вот скрипка для демонстрации - это намного проще, чем объяснять в письменной форме:

Анимированная демонстрация JSFiddle

person Alex    schedule 18.09.2017
comment
Анимация не была частью вопроса, но +1 за усилия и классное решение. - person Racil Hilan; 19.12.2017

Простой. Просто следуйте приведенному ниже коду:

HTML:

<div class="circle"></div>
<div class="pie"></div>

CSS:

.circle {
width: 11em;
height: 11em;
border-radius: 100%;
background: linear-gradient(360deg, #FFFFFF 100%, transparent 42.34%) 0 0;
background-repeat: no-repeat;
background-size: 100% 100%;
}

.pie {
width: 11em;
height: 11em;
border-radius: 100%;
background: linear-gradient(-80deg, #1BB90D 50%, transparent 40%) 0 0;
background-repeat: no-repeat;
background-size: 100% 55%;
position: relative;
margin-top: -176px;
border: 1px solid #808D1E;
}
person Rajnish    schedule 18.01.2014

Просто чтобы добавить к ответам, вы также можете сделать это, используя clip-path. Добавьте радиус границы 50% и clip-path со значением, полученным из следующей функции.

function calc_arc(prc) {
let str = '50% 50%, 50% 0%';
if(prc >= 45)
    str += ',100% 0%';
else
    str += ','+ (50+(prc/.45)/2) + '% 0%';

if(prc >= 135) 
    str += ',100% 100%';
else {

    prc -= 45;
    if(prc > 0) {
    prc /= .9;
    str += ',100% '+prc + '%';
    }
}

if(prc >= 225) 
    str += ',0% 100%';
else {
    prc -= 135;
    if(prc>0) {
    prc /= .9;
    str += ','+(100-prc) + '% 100%';
    }
}
if(prc >= 315) 
    str += ',0% 0%';
else {
    prc -= 225;
    if(prc>0) {
    prc /= .9;
    str += ',0% '+(100-prc) + '%';}
}
if(prc >= 360)
    str += ',100% 0%';
else {
prc -= 315;
if(prc>0) {
    str += ','+(prc/.45)/2 + '% 0%';
    }
    }
return 'polygon('+str+')';

}

Как это работает, он проверяет процент и на основе некоторых предварительно рассчитанных контрольных точек генерирует многоугольник для разрезания квадрата. Радиус границы превращает ее в сегмент окружности.

person Dapu    schedule 17.09.2019