Сайт о телевидении

Сайт о телевидении

» » Диаграммы только html и css3. Круговой индикатор процесса на CSS. Создание новой страницы

Диаграммы только html и css3. Круговой индикатор процесса на CSS. Создание новой страницы

Несмотря на то, что круговые диаграммы являются самым распространенным способом представления информации, начиная от простой статистики и заканчивая индикаторами прогресса и таймерами, даже в их простейшей двухцветной форме, они традиционно создавались какими угодно способами, кроме простых методов с использованием веб-технологий. Обычно для их реализации использовались либо внешние графические редакторы для создания нескольких изображений для нескольких значений круговой диаграммы , либо JavaScript фреймворки, предназначенные для создания более сложных диаграмм.

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

Решение на основе transform

Это решение является лучшим в плане разметки: для него необходим только один элемент, а всё остальное будет выполнено с помощью псевдоэлементов, преобразований и CSS градиентов. Давайте начнем с простого элемента:

Теперь давайте предположим, что нам нужна круговая диаграмма, которая отображает жестко заданные 20% . Над тем, чтобы она была гибкой, мы поработаем позже. Сначала стилизуем элемент как круг, который будет нашим фоном (рисунок 1):

Рисунок 1 - Наша отправная точка (круговая диаграмма, отображающая 0%) .pie { width: 100px; height: 100px; border-radius: 50%; background: yellowgreen; }

Наша круговая диаграмма будет зеленой (а конкретнее, yellowgreen) с коричневым сектором (#655), показывающим долю в процентах. У нас мог бы возникнуть соблазн использовать наклонные преобразования для процентной части, но как показывают небольшие эксперименты, это будет довольно неаккуратным решением. Вместо этого, мы раскрасим левую и правую части нашего круга в два цвета и используем вращение псевдоэлемента, чтобы раскрыть только ту долю круга, которая нам нужна .

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

Background-image: linear-gradient(to right, transparent 50%, #655 0); Рисунок 2 - Раскрашивание правой части нашего круга в коричневый цвет простым линейным градиентом

Как вы можете увидеть на рисунке 2, это всё, что нам требовалось. Теперь мы можем приступить к стилизации псевдоэлемента, который будет выступать в качестве маски:

Pie::before { content: ""; display: block; margin-left: 50%; height: 100%; } Рисунок 3 - Псевдоэлемент, действующий как маска, выделен здесь с помощью пунктирной границы

На рисунке 3 вы можете увидеть, как на данный момент расположен наш псевдоэлемент относительно элемента круговой диаграммы. Сейчас он пока не стилизован и не выполняет никаких функций. Это всего лишь невидимый прямоугольник. Перед тем, как приступить к его стилизации, давайте сделаем несколько замечаний:

  • так как мы хотим скрыть коричневую часть нашего круга , то мы должны применить к псевдоэлементу зеленый фон, используя background-color: inherit , чтобы избежать дублирования при назначении ему такого же цвета фона, как у родительского элемента;
  • мы хотим, чтобы он вращался вокруг центра круга , который находится на середине левой стороны псевдоэлемента, поэтому мы должны задать transform-origin значение 0 50% или просто left ;
  • мы не хотим, чтобы он был прямоугольником, так как при этом он выходит за края круговой диаграммы, поэтому мы должны либо применить overflow: hidden к.pie , либо задать ему border-radius , чтобы сделать его полукругом.

Сложив всё это вместе, мы получим следующий стиль для нашего псевдоэлемента;

Pie::before { content: ""; display: block; margin-left: 50%; height: 100%; border-radius: 0 100% 100% 0 / 50%; background-color: inherit; transform-origin: left; } Рисунок 4 - Наш псевдоэлемент (показан с пунктирной границей) после окончания стилизации

Примечание: Не используйте background: inherit;, вместо backround-color: inherit;, так как в этом случае будет унаследован и градиент!

Теперь наша круговая диаграмма выглядит, как на рисунке 4. Здесь и начинается самое интересное! Мы можем начать вращать псевдоэлемент , применяя преобразование rotate() . Для 20% , которые мы пытаемся реализовать, мы можем использовать значение 72deg (0.2 × 360 = 72), или.2turn , что более читаемо. На рисунке 5 вы можете увидеть, как это выглядит и для нескольких других значений.

Рисунок 5 - Наша простая круговая диаграмма, показывающая разные процентные доли, слева направо: 10% (36deg или.1turn), 20% (72deg или.2turn), 40% (144deg или.4turn)

Можно подумать, что дело сделано, но, к сожалению, не всё так просто. Наша круговая диаграмма отлично подходит для отображения процентных долей от 0 до 50%, но если мы попытаемся отобразить 60-процентный поворот (применив.6turn), получится то, что изображено на рисунке 6. Но всё же не теряйте надежду, мы можем это исправить и сделаем это!

Рисунок 6 - Наша круговая диаграмма ломается для долей более 50% (здесь показано для 60%)

Если рассматривать отображение долей 50%-100%, как отдельную проблему, то можно заметить, что для них мы можем использовать перевернутую версию предыдущего решения : коричневый псевдоэлемент, вращающийся, соответственно, от 0 до.5turn . Таким образом, для доли 60% код псевдоэлемента будет выглядеть следующим образом:

Pie::before { content: ""; display: block; margin-left: 50%; height: 100%; border-radius: 0 100% 100% 0 / 50%; background: #655; transform-origin: left; transform: rotate(.1turn); } Рисунок 7 - Наша, теперь правильная, круговая диаграмма со значением 60%

На рисунке 7 вы можете увидеть код в действии. Так как теперь мы разработали способ для отображения любой процентной доли, то можем и анимировать круговую диаграмму от 0% до 100% с помощью CSS анимации , создав своеобразный индикатор прогресса:

@keyframes spin { to { transform: rotate(.5turn); } } @keyframes bg { 50% { background: #655; } } .pie::before { content: ""; display: block; margin-left: 50%; height: 100%; border-radius: 0 100% 100% 0 / 50%; background-color: inherit; transform-origin: left; animation: spin 3s linear infinite, bg 6s step-end infinite; }

Всё хорошо, но как нам стилизовать несколько статических круговых диаграмм с различными процентными долями, что и является наиболее общим случаем использования диаграмм? В идеале, мы хотим, чтобы была возможность напечатать что-то вроде этого:

20% 60%

И получить две круговые диаграммы, одна из которых показывает 20%, а другая - 60%. Во-первых, мы рассмотрим, как можно это сделать с помощью встроенных стилей, а затем мы всегда можем написать короткий скрипт для разбора текстового контента и добавить указанные встроенные стили для элегантности кода, инкапсуляции, поддерживаемости и, возможно, самое главное, доступности.

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

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

Решение приходит из одного из самых неожиданных мест. Мы собираемся использовать анимацию, которую уже показали, но которая будет поставлена на паузу. Вместо того, чтобы запускать ее, как обычную анимацию, мы будем использовать отрицательные задержки анимации, чтобы задать положение в любой точке анимации и остаться там. Удивлены? Да, отрицательные значения animation-delay не только разрешены в спецификации, но и очень полезны в подобных случаях.

Так как наша анимация приостановлена, будет показан только первый ее кадр (определяется нашим отрицательным значением animation-delay). Процентная доля, показанная на круговой диаграмме, будет равна процентной доле, которую составляет наш animation-delay в общей продолжительности. Например, с текущей продолжительностью 6s , нам необходимо значение animation-delay , равное -1.2s , чтобы показать долю 20%. Для упрощения вычислений мы будем устанавливать продолжительность в 100s . Имейте в виду, что, так как анимация остановлена навсегда, значение ее продолжительности, которое мы устанавливаем, не играет никакой другой роли.

И последний вопрос: анимация применяется к псевдоэлементу, но мы хотим установить встроенный стиль на элемент.pie . Тем не менее, хотя на нет анимации, мы можем установить для него animation-delay , как встроенный стиль, а затем использовать animation-delay: inherit; для псевдоэлемента. Сложив всё это вместе, наша разметка для 20% и 60% круговых диаграмм будет выглядеть следующим образом:

И CSS код для этой анимации станет следующим (правила для.pie не показаны, так как остались теми же):

@keyframes spin { to { transform: rotate(.5turn); } } @keyframes bg { 50% { background: #655; } } .pie::before { /* [остальные стили не изменились] */ animation: spin 50s linear infinite, bg 100s step-end infinite; animation-play-state: paused; animation-delay: inherit; }

На данный момент мы можем преобразовать разметку для использования процентов в качестве контента, как мы изначально и собирались сделать, и добавить встроенные стили animation-delay через простой скрипт:

$$(".pie").forEach(function(pie) { var p = parseFloat(pie.textContent); pie.style.animationDelay = "-" + p + "s"; });

Обратите внимание, что мы оставили нетронутым текст, так как он необходим нам для доступности и удобства использования. Сейчас наши круговые диаграммы выглядят, как на рисунке 8. Мы должны скрыть текст, который можно сделать доступным через color: transparent так, чтобы он оставался выбираемым и печатаемым . Для дополнительного глянца мы можем поместить значения процентов в центр круговой диаграммы , чтобы они не находились в случайном месте, когда пользователь попытается выделить их. Чтобы сделать это, нам необходимо:

Рисунок 8 - Наш текст перед тем, как мы спрячем его

  • преобразовать значение height диаграммы в line-height (или добавить значение line-height , равное height , но это будет бессмысленным дублированием кода, так как line-height будет установлено в вычисленное значение height , что хорошо);
  • задать размер и положение псевдоэлемента с помощью абсолютного позиционирования , чтобы он не толкал текст вниз;
  • добавить text-align: center; , чтобы отцентрировать текст по горизонтали.

Окончательный код выглядит так:

Pie { position: relative; width: 100px; line-height: 100px; border-radius: 50%; background: yellowgreen; background-image: linear-gradient(to right, transparent 50%, #655 0); color: transparent; text-align: center; } @keyframes spin { to { transform: rotate(.5turn); } } @keyframes bg { 50% { background: #655; } } .pie::before { content: ""; position: absolute; top: 0; left: 50%; width: 50%; height: 100%; border-radius: 0 100% 100% 0 / 50%; background-color: inherit; transform-origin: left; animation: spin 50s linear infinite, bg 100s step-end infinite; animation-play-state: paused; animation-delay: inherit; }

Решение на основе SVG

SVG делает решение многих графических задач проще, и круговые диаграммы не являются исключением. Тем не менее, вместо создания круговой диаграммы с помощью путей, что потребовало бы сложной математики, мы воспользуемся небольшой хитростью.

Начнем с круга:

Теперь применим к нему несколько базовых стилей:

Circle { fill: yellowgreen; stroke: #655; stroke-width: 30; }

Примечание : Как вы знаете, эти CSS свойства также доступны в качестве атрибутов SVG элемента, которые могли бы быть удобны, если бы портирование доставляло беспокойство.

Рисунок 9 - Наша начальная точка: зеленый SVG круг с толстой #655 обводкой

Наш обведенный круг вы можете увидеть на рисунке 9. Обводки в SVG состоят не только из свойств stroke и stroke-width . Есть много других, менее популярных свойств, связанных с обводками, которые позволяют точно настроить их внешний вид. Одним из них является stroke-dasharray , предназначенное для создания пунктирных обводок. Например, мы могли бы использовать его для этого:

Stroke-dasharray: 20 10; Рисунок 10 - Простая пунктирная обводка, созданная с помощью stroke-dasharray

Это означает, что мы хотим получить тире длиной 20 с промежутками длиной 10 , как те, что изображены на рисунке 10. В этот момент вы можете быть удивлены, что этот SVG пример имеет что-то общее с круговыми диаграммами. Но всё становится яснее, когда мы применим обводку с длиной тире 0 и промежутками длиной больше или равной длине окружности нашего круга (C = 2πr, или в нашем случае C = 2π × 30 ≈ 189):

Stroke-dasharray: 0 189; Рисунок 11 - Несколько значений stroke-dasharray и их результат; слева направо: 0 189 ; 40 189 ; 95 189 ; 150 189

Как вы можете видеть, в первом круге на рисунке 11 это полностью удаляет обводку, и мы остаемся только с зеленым кругом. Однако веселье начинается, когда мы начинаем увеличивать первое значение (рисунок 11): из-за такого длинного разрыва мы получим уже не пунктирную обводку, а обводку, которая покрывает такую процентную долю окружности круга, какую мы укажем.

Возможно, вы уже поняли, в какую сторону мы двигаемся: если уменьшить радиус нашего круга достаточно, чтобы он полностью закрывался своей обводкой, мы, в конечном итоге, получим что-то, очень напоминающее круговую диаграмму. Например, на рисунке 12 вы можете увидеть, как это будет выглядеть при применении к кругу с радиусом 25 и шириной обводки (stroke-width) 50:

Рисунок 12 - Наше SVG изображение начинает напоминать круговую диаграмму

Помните: SVG обводки всегда наполовину внутри и наполовину снаружи элемента, к которому они применяются. В будущем нам будет доступно управление этим поведением.

circle { fill: yellowgreen; stroke: #655; stroke-width: 50; stroke-dasharray: 60 158; /* 2π × 25 ≈ 158 */ }

Теперь превратить это изображение в круговую диаграмму, подобную тем, что мы создали в предыдущем решении, довольно легко: нужно просто добавить больший зеленый круг под обводку и повернуть его на 90° против часовой стрелки так, чтобы он начинался вверху в середине. Поскольку элемент также является и HTML элементом, мы можем просто применить к нему стиль:

Svg { transform: rotate(-90deg); background: yellowgreen; border-radius: 50%; } Рисунок 13 - Конечная круговая диаграмма с SVG

Вы можете увидеть окончательный результат на рисунке 13. Этот метод делает еще проще анимацию круговой диаграммы от 0% до 100% . Нам просто нужно создать CSS анимацию, которая изменяет stroke-dasharray от 0 158 до 158 158:

@keyframes fillup { to { stroke-dasharray: 158 158; } } circle { fill: yellowgreen; stroke: #655; stroke-width: 50; stroke-dasharray: 0 158; animation: fillup 5s linear infinite; }

В качестве дополнительного усовершенствования мы можем задать определенный радиус круга так, чтобы длина его окружности составляла (бесконечно близко к) 100, и поэтому мы сможем указывать длины stroke-dasharray , как проценты , без каких-либо расчетов. Поскольку длина окружности равна 2πr, нам необходим радиус 100 ÷ 2π ≈ 15.915494309, который для наших нужд может быть округлен до 16. Также мы зададим размеры SVG в атрибуте viewBox , вместо атрибутов width и height , чтобы сделать его подстраиваемым под размеры его контейнера.

После этих модификаций разметка круговой диаграммы, изображенной на рисунке 13, станет следующей:

А CSS станет таким:

Svg { width: 100px; height: 100px; transform: rotate(-90deg); background: yellowgreen; border-radius: 50%; } circle { fill: yellowgreen; stroke: #655; stroke-width: 32; stroke-dasharray: 38 100; /* для 38% */ }

Обратите внимание, как легко теперь изменить процентную долю . Хотя даже с таким упрощением мы не хотим повторять всю эту SVG разметку для каждой круговой диаграммы. Пришло время JavaScript, чтобы помочь нам небольшой автоматизацией. Мы напишем небольшой скрипт, чтобы взять простую HTML разметку, подобную этой...

20% 60%

И добавить встроенный SVG внутрь каждого элемента.pie со всеми необходимыми элементами и атрибутами. Он также добавит элемент для доступности так, чтобы пользователи экранных дикторов также могли узнать, какие проценты отображаются. Окончательный скрипт будет выглядеть следующим образом:

$$(".pie").forEach(function(pie) { var p = parseFloat(pie.textContent); var NS = "http://www.w3.org/2000/svg"; var svg = document.createElementNS(NS, "svg"); var circle = document.createElementNS(NS, "circle"); var title = document.createElementNS(NS, "title"); circle.setAttribute("r", 16); circle.setAttribute("cx", 16); circle.setAttribute("cy", 16); circle.setAttribute("stroke-dasharray", p + " 100"); svg.setAttribute("viewBox", "0 0 32 32"); title.textContent = pie.textContent; pie.textContent = ""; svg.appendChild(title); svg.appendChild(circle); pie.appendChild(svg); });

Вот оно! Вы можете подумать, что CSS метод лучше, так как его код проще и более знаком. Однако SVG метод имеет определенные преимущества перед решением на чистом CSS:

  • проще добавить третий цвет : просто добавьте еще один обведенный круг и передвиньте его обводку с помощью stroke-dashoffset . Или добавьте длину его обводки к длине обводки предыдущего круга перед (под) ним. Как именно вы добавите третий цвет к круговой диаграмме, созданной первым способом?
  • мы не должны прикладывать каких-либо дополнительных усилий для печати , так как SVG элементы рассматриваются, как контент и печатаются так же, как элементы . Первое решение зависит от фона и, таким образом, будет не напечатано;
  • мы можем изменять цвета с помощью встроенных стилей , что означает, что мы можем легко изменять их через скрипты (т.е. в зависимости от ввода пользователя ). Первое решение опирается на псевдоэлементы, которые не могут принимать встроенные стили, кроме как через наследование, что не всегда удобно.
  • background: conic-gradient(#655 attr(data-value %), yellowgreen 0);

    Это также делает невероятно простым добавление третьего цвета. Например, для круговой диаграммы, подобной диаграмме, приведенной выше, мы бы просто добавили еще две цветовые остановки:

    Background: conic-gradient(deeppink 20%, #fb3 0, #fb3 30%, yellowgreen 0);

    Вот и всё! Оставляйте комментарии!

Такие индикаторы загрузки вы наверняка встречали, особенно на Flash сайтах. Это сектор круга, который становится все больше и больше, пока не превратится в завершенный круг.

На первый взгляд задача кажется простой: делаем круг, вращаем его и скрываем часть за маской. Но на деле все оказывается несколько сложнее. CSS не подготовлен для решения таких задач, даже при использовании препроцессоров наподобие SASS & Compass. Мы всегда боремся, когда приходится делать различные формы, а особенно при определении стилей и анимации для них. Большая часть рабочего времени уходит на то. чтобы получить что-то работающее, а в жертву приносится семантичность кода и его поддержка.

Зачем делаем?

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

Хотя есть несколько изумительных инструментов для управления круговыми диаграммами (в основном, на JavaScript), мы тем не менее сделаем такой элемент только на CSS и даже анимируем его с помощью нескольких трюков.

Семантичность кода будет так себе! Но сопровождение можно сделать достаточно удобным.

HTML

Нам нужно 3 разных элемента:

  • spinner: половинка круга, которая будет вращаться;
  • mask: данный элемент скрывает вращающийся круг в ходе первых 50% анимации;
  • filler: данный элемент заполняет круг в ходе последних 50% анимации.

И все три элемента должны иметь одного родителя для абсолютного позиционирования:

Так как spinner и filler являются двумя половинками одного круга, то мы будем использовать для них класс.pie .

CSS

Родительский элемент получает размеры и абсолютное позиционирование контекста для таймера:

Wrapper { width: 250px; height: 250px; position: relative; background: white; }

Важно, чтобы ширина и высота были равны, чтобы получить круг и все работало.

Элементы "spinner " и "filler " используют данный код CSS:

Pie { width: 50%; height: 100%; position: absolute; background: #08C; border: 10px solid rgba(0,0,0,0.4); }

Они имеют ширину равную 50% родительского элемента, так они являются двумя частями одного круга, а их высота равна высоте родительского элемента. Также мы определяем для них одинаковый цвет и рамку.

Элемент "spinner"

Spinner { border-radius: 125px 0 0 125px; z-index: 200; border-right: none; animation: rota 10s linear infinite; }

Делаем его полукругом с помощью свойства border-radius на верхнем левом и нижнем левом углах. Также определяем положительное значение для z-index , чтобы разместить его поверх заполняющего элемента, но ниже маски.

Затем добавляем animation длительностью 10 секунд. Об анимации мы поговорим позже.

Элемент "filler"

Filler { border-radius: 0 125px 125px 0; z-index: 100; border-left: none; animation: fill 10s steps(1, end) infinite; left: 50%; opacity: 0; }

Для данного элемента устанавливаем border-radius и z-index , удаляем border-left , и делаем анимацию длительностью 10секунд. Для данного элемента animation-timing-function не получает значения linear , но будет steps(1, end) . Это значит, что animation будет выполняться мгновенно.

Так как заполняющий элемент не должен быть видимым в ходе первой половины анимации, его непрозрачность будет 0, а положение - 50% ширины родительского элемента.

Элемент "mask"

Mask { width: 50%; height: 100%; position: absolute; z-index: 300; opacity: 1; background: inherit; animation: mask 10s steps(1, end) infinite; }

Маска присутствует с начала анимации, поэтому ее непрозрачность имеет значение 1, а фон наследуется от родительского элемента (чтобы она была невидима). Чтобы закрывать вращающийся элемент, она будет иметь те же размеры, а свойство z-index устанавливается в значение 300.

Кадры анимации

@keyframes rota { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } @keyframes fill { 0% { opacity: 0; } 50%, 100% { opacity: 1; } } @keyframes mask { 0% { opacity: 1; } 50%, 100% { opacity: 0; } }

Первая анимация (rota) используется для элемента spinner . Он постепенно вращается от 0 до 360 градусов за 10 секунд.

Вторая анимация (fill) используется для элемента filler . Он немедленно изменяет непрозрачность с 0 до 1 по истечении 5 секунд.

Последняя анимация (mask) используется для элемента mask . Он немедленно изменяет непрозрачность с 1 до 0 по истечении 5 секунд.

Анимация имеет следующий вид:

  • T0 - элемент spinner слева, скрыт маской. Элемент filler скрыт.
  • T1 - элемент spinner начинает вращаться по часовой стрелке и медленно появляется из-за маски.
  • T2 - элемент spinner r повернут на угол 360/10*2 = 72° продолжает вращаться.
  • T3 - элемент spinner повернут на угол 360/10*3 = 108° продолжает вращаться.
  • T4 - элемент spinner повернут на угол 360/10*4 = 144° продолжает вращаться.
  • T5 - элемент spinner повернут на угол 360/10*5 = 180° продолжает вращаться. В данный момент элемент filler мгновенно становится видимым, а маска скрывается.
  • T6 - элемент spinner повернут на угол 360/10*6 = 216° продолжает вращаться.
  • T7 - элемент spinner повернут на угол 360/10*7 = 252° продолжает вращаться.
  • T8 -элемент spinner повернут на угол 360/10*8 = 288° продолжает вращаться.
  • T9 - элемент spinner повернут на угол 360/10*9 = 324° продолжает вращаться.
  • T10 - элемент spinner повернут на угол 360°. Вернулись к точке старта. Сбрасываем анимацию. Маска появляется, а заполняющий элемент скрывается.
Бонус

Несколько дополнительных трюков.

Пауза при наведении курсора

Wrapper:hover .filler, .wrapper:hover .spinner, .wrapper:hover .mask { animation-play-state: paused; }

С помощью данного кода вы можете остановить всю анимацию при наведении курсора на родительский элемент.

Вставляем содержание

Благодаря свойству z-index мы можем легко добавить какое-нибудь содержание в элемент spinner и заставить его вращаться. Попробуйте следующий код:

Spinner:after { content: ""; position: absolute; width: 10px; height: 10px; border-radius: 50%; top: 10px; right: 10px; background: #fff; border: 1px solid rgba(0,0,0,0.4); box-shadow: inset 0 0 3px rgba(0,0,0,0.2); }

Препроцессор или переменные CSS

В текущий момент код очень не просто поддерживать. Но если мы используем переменные (в препроцессоре или ожидаемые внутренние переменные CSS), все может стать существенно проще. Например, можно добавить переменные для управления длительностью вместо того, чтобы исправлять код в 3 определениях анимаций.

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

Animation-duration { animation-duration: 10s; }

Недостатки

Данная техника имеет ряд недостатков:

  • Не поддерживаются градиенты.
  • Не поддерживаются тени.
  • Нет адаптивности. Если изменяется размер родительского элемента, то все будет нормально, кроме радиуса закругления рамки. Его придется менять вручную.
  • Нет семантичности (4 элемента для одной анимации).
Поддержка браузеров

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

  • Internet Explorer 10
  • Firefox 12+
  • Chrome
  • Safari 5+
  • Opera 12+
  • iOS Safari 3+
  • Android 2+
  • Перевод
  • Tutorial

Формы это неплохой способ добавить некую изюминку элементам на вашей веб странице. Круги особенно хороши в этом отношении, потому что они целостны, просты и похожи на пирог. А теперь серьёзно, кто не любит пироги?

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

Итак, начнём! При написании этого туториала, я буду работать с Circliful . Это бесплатный jQuery плагин с открытыми исходниками. Вы можете загрузить основной файл с Github . Он включает.js файл вместе с соответствующей CSS таблицей стилей. Страница должна содержать и то и другое, чтобы добиться эффекта круга.

Animated Circle Stats - Template Monster Demo

Моя страница содержит подобную таблицу стилей styles.css для моих личных CSS стилей. Вам также необходимо сделать копию библиотеки jQuery . Она необходима для того, чтобы плагин корректно работал.
Саму по себе, страницу довольно легко структурировать. Элементы круга содержатся в тэгах div, которые используют атрибуты HTML5 для управления данными. В качестве альтернативы, они могут храниться в функции jQuery, но если вы хотите лучше контролировать каждый элемент, тогда проще работать в HTML.

Photoshop Illustrator After Effects

Это копия первого ряда кругов, состоящего из 3 анимированных единиц. Все эти атрибуты данных в дальнейшем разъяснены в документации к плагину . Каждый представляет опцию, которая определяет анимационный эффект. Ниже привожу краткое описание опций, которые я использую:

  • data-dimension – общий размер круга ширина/высота;
  • data-text – текст, который появляется в центре каждого круга;
  • data-width – толщина вращающейся дуги данных;
  • data-fontsize – размер шрифта текста по центру;
  • data-percent – число от 0-100 отображающее проценты в вашем круге;
  • data-fgcolor – цвет переднего плана круга;
  • data-bgcolor – цвет фона круга;
  • data-fill – внутренняя заливка цвета фона внутреннего круга.
Компоновка CSS страницы Я не настаиваю на том, чтобы вы напрямую редактировали jquery.circliful.css , конечно если вы не желаете кастомизировать плагин. Большая часть цветов может быть изменена прямо из атрибутов данных HTML5, и если вы действительно хотите переписать какие-либо из стилей Circliful , я бы рекомендовал вам делать это в своей собственной таблице стилей.
Сказав вам это, я создал свою собственную таблицу стилей для данного проекта, а не для того, чтобы переписывать стили Circliful . Сама по себе веб страница нуждается в компоновке по умолчанию, которую действительно легко спроектировать. Контентная область отцентрирована в маленькой секции для круговой диаграммы. Каждая область свободно перемещается в контейнере строки в пределах оригинального #stats div .

/** page structure **/ .wrap { display: block; margin: 0 auto; max-width: 800px; } #intro { display: block; margin-bottom: 25px; text-align: center; } #intro p { font-size: 1.8em; line-height: 1.35em; color: #616161; font-style: italic; margin-bottom: 25px; } #stats { display: block; width: 100%; padding: 15px 0; background: #f8f8f8; border-top: 4px solid #c3c3c3; border-bottom: 4px solid #c3c3c3; } #stats .row { display: block; } .circle-container { display: block; float: left; margin-right: 55px; margin-bottom: 45px; } .circle-container h3 { display: block; text-align: center; font-size: 2.25em; line-height: 1.4em; color: #363636; text-shadow: 1px 1px 0 #fff; }

Внутри каждой секции, контент удерживается в пределах .wrap div для фиксации в центре. Также, свободно передвигающимся элементам круга необходим дополнительный контейнер .clearfix , для того чтобы всё оставалось правильно выровненным.

/** clearfix **/ .clearfix:after { content: "."; display: block; clear: both; visibility: hidden; line-height: 0; height: 0; } .clearfix { display: inline-block; } html .clearfix { display: block; } * html .clearfix { height: 1%; }

Этот класс clearfix был известен годами как решение для контейнера со свободно двигающимися элементами. Обычно их удаляют из текста документа и не сохраняют значение их оригинальной ширины/высоты. Но это поддерживает постоянную ширину контейнера #stats и оставляет место для большего количества контента, который будет располагаться ниже на странице.

Заключительные штрихи Так, мы замесили тесто, заполнили противень для пирога, поместили его в духовку и уже практически готовы снять пробу. Если всё выглядит достаточно хорошо, то каков же будет финальный шаг? Нам нужно немного jQuery кода в качестве украшения этого проекта.
Откройте новый скрипт тэг внизу этой HTML страницы. Он будет содержать небольшой отрывок JavaScript. Так как я использовал все атрибуты данных HTML5, нам не нужно вызывать никаких jQuery опций. Скрипт просто должен запустить функцию Circliful на каждом круге divs. Используя продублированное название класса, как например, .circlestat делает процесс очень простым.

$(function(){ $(".circlestat").circliful(); });

Для тех, кто не знаком с синтаксической структурой jQuery, я предоставлю короткое описание. После того, как документ загрузится, мы запускаем новую функцию. Нашей внутренней целью является каждый элемент, который использует класс .circlestat и запускает функцию circliful() . Это приводит плагин Circliful , который создаёт анимационные эффекты, в действие и применяет дополнительный контент/цвета.

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

"Кухня" веб-разработчика отчасти похожа на домашнюю кухню. Разработчик имеет доступ к разнообразию библиотек из готового кода, которые помогут ему сделать веб-приложение практически так же, как повар дома может использовать полуфабрикаты, чтобы приготовить свое блюдо более эффективно. В обоих случаях качество предварительно подготовленных вещей должно быть очень важно. Однако, иногда качество приносится в жертву удобству. Не поймите меня неправильно, удобство - не всегда плохо. Оно может быть полезно, когда плюсы и минусы известны и хорошо проанализированы. Анализируя варианты для круговых и кольцевых диаграмм в HTML, мы можем выделить лишь несколько:

  • Диаграмма, основанная на элементе Canvas, сгенерированная на клиенте (т.е. JavaScript)
  • Диаграмма, основанная на SVG и сгенерированная на клиенте (т.е. JavaScript)
  • Диаграмма, основанная на SVG и сгенерированная на сервере
  • Готовые библиотеки с использованием Canvas и SVG JavaScript

    JavaScript-библиотеки для отрисовки диаграмм часто более удобные и загруженные кучей классных опций типа интерактивности. Вот несколько библиотек:

  • D3.js
  • Chartist.js
  • Google Charts
  • Несколько строчек на JavaScript и массив данных позволят вам создать диаграмму на сайте за секунды. Неудивительно, что многие выбирают этот путь.

    Так зачем заморачиваться и писать код для них своими руками? Это отличный вопрос, который я также задал себе. В конце концов, я убедился в трех вещах:

  • Большинство JavaScript-библиотек являются труднодоступными, особенно те, что основаны на элементе Canvas (за исключением Google Charts)
  • Если информация в диаграмме очень важна (как это было в моей ситуации), должны ли мы рассчитывать на скрипт, выполняющийся на клиенте, чтобы генерировать информацию? Я так не думаю.
  • Если я копну SVG-код глубже и запачкаю руки, я могу узнать немного больше про ту лежащую в его основе магическую чепуху. Другими словами, процесс обучения может оказаться веселым и стоящим моих усилий.
  • Моя ситуация

    Моей команде нужен был простой компонент, который мог быть собран на сервере и отображать простую информацию об использовании аккаунтов. Кроме того, нашим предпочтением была легкость этого компонента (избежание JavaScript, если возможно); он не должен был быть чрезмерно мудреным или интерактивным, от него нужно было только отображение важных данных.

    Дополнительная заметка о диаграммах, основанных на элементе Canvas

    Вы могли заметить (если знакомы с созданием диаграмм для веба), что я не включил Chart.js в список рекомендованных библиотек выше. Хотя вы определенно можете ее использовать, стоит иметь в виду, что Chart.js использует элемент Canvas для отрисовки его диаграмм, и содержание элемента не является частью DOM. Следовательно, они недоступны для программ чтения с экрана. Это значит, что вам придется принять дополнительные меры, чтобы убедиться в доступности ваших данных.

    Введение в CSS и SVG диаграммы

    CSS- и SVG-диаграммы по своей сути более доступные и семантические, чем остальные технологии. Но они могут быть сложными, и, возможно, занимающими больше времени, если писать их код вручную.

    CSS-ниндзя Леа Вероу предлагает несколько вариантов создания круговых диаграмм с нуля в ее статье "Designing Flexible, Maintainable Pie Charts With CSS and SVG" ("Разрабатываем гибкие, поддерживаемые круговые диаграммы с помощью CSS и SVG"). Ее методы могут быть применимы и для кольцевых диаграмм.

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

    Необъяснимое

    Я немного погуглил про SVG и кольцевые диаграммы и столкнулся со статьями Леа Вероу и Робина Рэндла (они упомянуты выше) в дополнении к еще нескольким. Почти во всех из них обсуждалось использование атрибутов stroke-dasharray и stroke-dashoffset в SVG для расположения частей диаграммы. Эти свойства идентичны " stroke " при создании векторов в программах типа Adobe Illustrator.

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

    После моего исследования я смог понять, что использование из SVG вместе с stroke и stroke-dasharray могло обеспечить мне те сегменты вложенной круговой диаграммы, что были мне нужны. Я также понял, что stroke-dashoffset позволит мне сделать "анимацию", или, другими словами, расположить сегмент в том месте круга, где я хотел.

    Однако, кажется, я не нашел никакого четкого объяснения тому, как именно работали stroke dash атрибуты и какое они имели отношение к окружности круга. А что было более недостижимым, так это прикрепление нескольких элементов (один за другим) вокруг круга. Еще лучше, какова же формула получения этих относительных позиций с использованием уникальных/динамических размеров сегментов и stroke-атрибутов SVG?

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

    Примечание: Если вы нашли какие-либо ресурсы, объясняющие эти концепты, пожалуйста, поделитесь. Как сделать SVG-диаграмму своими руками Объяснение stroke-dasharray и stroke-dashoffset

    Давайте начнем с простой SVG-"кольцевой диаграммы".

    Вы заметите пару вещей:

  • Радиус (атрибут "r") выглядит абсурдно! Почему? Я хотел сделать размеры моих сегментов логичными, доступными для понимания и читабельными. Для того, чтобы достичь этого, я решил основать все на 100% (или на окружности, равной 100). SVG-фигуры масштабируемы, так что не очень важно, насколько большими они в конце концов окажутся; по крайней мере, математика здесь будет проста. Заходим дальше в ту область, что я помню из математики старшей школы: я знаю, что радиус окружности равен r = C/(2π) или r = 100/(2π). Результат равен 15.91549430918952. Безумное число с кучей цифр, да, знаю, но позже оно облегчит нам всем жизни.
  • Для viewBox заданы значения " 0 0 42 42 ". Они должны быть удвоенными cx & cy (center x и center y) значениями и быть чуть больше, чем диаметр кругов (включая ширину контура).
  • Там есть с классом " donut-hole ". Вот что гарантированно делает центр белым. Если вам это не важно (в случае с простой круговой диаграммой), тогда этот пункт можно убрать.
  • Также там есть с классом " donut-ring ". Он служит в качестве светло-серого фона в случае, если секторы не заполняют 100% окружности.
  • Итак, нам необходимо скорректировать размер сектора до желаемого процента. Давайте используем 85%:


    Сектора созданы с помощью использования SVG stroke -атрибута, называемого stroke-dasharray . Значение, которое мы задали в примере выше, равняется " 85 15 ".

    Если мы будем думать о диаграмме, как о круговой, то из наличия 85%-го сектора можно судить об остатке в 15%. Эти два значения - это массив, разграниченный пробелом. Вот что происходит: создаётся черта в 85 единиц, затем пробел в 15 единиц, затем черта в 85, пробел в 15 и так далее и тому подобное. Но поскольку мы используем круг, и общее значение равняется 100, все повторяется снова. Если мы не сделали второе значение в массиве таким, что оно дополняет первое число до ста, то мы получим третью черту (или часть) или больше. Например, вот stroke-dasharray от " 10 10 ":


    Так, на фигуре 2 и фигуре 3 вы можете заметить, что stroke-dasharray не начинается на самом верху (на 12:00). Вместо этого, на самом деле оно начинается на правой стороне (3:00), и движется по часовой стрелке по кругу.

    Если мы хотим расположиться (или начать) сверху, то мы должны использовать stroke-dashoffset . Однако в отличие от stroke-dasharray , stroke-dashoffset двигается против часовой стрелки. Итак, нам необходимо будет задать значение " 25 " (на 25% в другую сторону от 3:00, назад к 12:00). Помните, что это - не отрицательное число, потому что offset движется против стрелки.


    Как расположить сектора кольцевой диаграммы вокруг SVG

    Теперь нам нужно добавить дополнительные сектора вокруг круга. Давайте используем сектор, занимающий 15% от окружности. Оставшийся процент для stroke-dasharray будет равен 85%, независимо от любых других секторов. Следовательно, код будет выглядеть так:

    Мы оставили stroke-dashoffset на значении 25 , поэтому зеленый сектор начинается сверху и идет по часовой стрелке, перекрывая первый сектор (розовый).


    Очевидно, это не совсем то, чего мы хотели. Мы хотим, чтобы пятнадцатый процент (зеленый цвет) впритык вписывался в пространство, оставленное восемьдесят пятым процентом (розовый). Мы можем корректировать stroke-dashoffset , пока не повезет, но это было бы не так просто, имей мы еще два сектора. Вместо этого нам нужна формула:

    Окружность - общая длина всех предыдущих секторов + смещение первого сектора = смещение текущего сектора

    Подключая наши числа, мы получаем:


    Добавляем больше секторов нашей диаграмме!

    Эта же самая формула работает для добавления дополнительных секторов. Давайте заполним диаграмму 40, 30, 20 процентами, и оставшиеся 10 не будут использованы.

    Результат:


    Добавляем текст внутрь диаграммы

    Это не была бы кольцевая диаграмма без текста внутри и посередине; для этого и предназначена дыра, правильно? Что ж, добавить текст просто. Мы просто используем элемент , который нативен для SVG-фигур.

    10 Beers

    Вы заметите, что я разделил текст диаграммы на 2 элемента и сгруппировал их (). Это было сделано затем, чтобы мы могли легче наложить заголовок и число друг на друга, а также расположить их, как одну единицу. Я настроил атрибуты X и Y так, чтобы начать с центра фигуры на линии основания и выровнить их по левому краю.


    Как вы можете увидеть, позиционирование не совсем верно, так что нам надо будет украсить его капелькой CSS:

    @import url(https://fonts.googleapis.com/css?family=Montserrat:400); .chart-text { font: 16px/1.4em "Montserrat", Arial, sans-serif; fill: #000; -moz-transform: translateY(0.25em); -ms-transform: translateY(0.25em); -webkit-transform: translateY(0.25em); transform: translateY(0.25em); } .chart-number { font-size: 0.6em; line-height: 1; text-anchor: middle; -moz-transform: translateY(-0.25em); -ms-transform: translateY(-0.25em); -webkit-transform: translateY(-0.25em); transform: translateY(-0.25em); } .chart-label { font-size: 0.2em; text-transform: uppercase; text-anchor: middle; -moz-transform: translateY(0.7em); -ms-transform: translateY(0.7em); -webkit-transform: translateY(0.7em); transform: translateY(0.7em); }

    Для начала, давайте добавим шрифт Montserrat (просто потому, что он мне нравится). Затем нам надо скорректировать font-size ("размер шрифта") и line-height ("высота строки"). После добавления " translateY " в 0.25em текст немного выравнивается по вертикали, но на этом мы еще не закончили.

    Нам надо сделать оба текстовых блока меньше и выровнять их до центра, корректируя font-size дотуда, докуда нам нравится (0.6em для более крупного числа и 0.2em для названия выглядят, что надо) и используя свойство " text-anchor " со значением " middle ".

    Теперь текст находится в центре. Все, что осталось, это сделать его в верхнем регистре (это легко) и расположить его индивидуальные элементы, используя " translateY ", чтобы они сложились должным образом. И вот что мы имеем сейчас:


    Проблемы с доступностью

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

    Первый уровень проблем с доступностью - сделать SVG-диаграмму более семантической, обернув ее в элемент (поскольку это - диаграмма). Как фигура, мы можем воспользоваться элементом , чтобы предоставить заголовок или описание для кольцевой диаграммы.

    Помимо этого, мы можем добавить контент-теги и (которые нативны для SVG) и связать их с заголовками ARIA, ID и ролью "предоставления большего количества контекста для программ чтения с экрана".

    @import url(https://fonts.googleapis.com/css?family=Montserrat:400); body { font: 16px/1.4em "Montserrat", Arial, sans-serif; } * { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } .chart-text { /*font: 16px/1.4em "Montserrat", Arial, sans-serif;*/ fill: #000; -moz-transform: translateY(0.25em); -ms-transform: translateY(0.25em); -webkit-transform: translateY(0.25em); transform: translateY(0.25em); } .chart-number { font-size: 0.6em; line-height: 1; text-anchor: middle; -moz-transform: translateY(-0.25em); -ms-transform: translateY(-0.25em); -webkit-transform: translateY(-0.25em); transform: translateY(-0.25em); } .chart-label { font-size: 0.2em; text-transform: uppercase; text-anchor: middle; -moz-transform: translateY(0.7em); -ms-transform: translateY(0.7em); -webkit-transform: translateY(0.7em); transform: translateY(0.7em); } figure { display: flex; justify-content: space-around; flex-direction: column; margin-left: -15px; margin-right: -15px; } @media (min-width: 768px) { figure { flex-direction: row; } } .figure-content, .figure-key { flex: 1; padding-left: 15px; padding-right: 15px; align-self: center; } .figure-content svg { height: auto; } .figure-key { min-width: calc(8 / 12); } .figure-key { margin-right: 6px; } .figure-key-list { margin: 0; padding: 0; list-style: none; } .figure-key-list li { margin: 0 0 8px; padding: 0; } .shape-circle { display: inline-block; vertical-align: middle; width: 32px; height: 32px; -webkit-border-radius: 50%; -moz-border-radius: 50%; border-radius: 50%; } .shape-fuschia { background-color: #ce4b99; } .shape-lemon-lime { background-color: #b1c94e; } .shape-blue { background-color: #377bbc; } .sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0,0,0,0); border: 0; } Beers in My Cellar Belgian Quadrupels Pink chart segment spanning 40% of the whole, which is 4 Belgian Quadrupels out of 10 total. Imperial India Pale Ales Green chart segment spanning 20% of the whole, which is 2 Imperial India Pale Ales out of 10 total. Russian Imperial Stouts Blue chart segment spanning 3% of the whole, which is 3 Russian Imperial Stouts out of 10 total. 10 Beers

    Donut chart showing 10 total beers. Two beers are Imperial India Pale Ales, four beers are Belgian Quadrupels, and three are Russian Imperial Stouts. The last remaining beer is unlabeled.

    Мы также можем добавить ключ легенды для диаграммы в качестве части , отмечая его ролью "представления" и атрибутом aria-hidden , поскольку он и вправду нужен для наглядности.

    С щепоткой магии CSS Flexbox мы можем расположить ключ справа и выровнять его по вертикали с диаграммой. Что даст нам финальный продукт:


    Поскольку CSS-дизайн с ключом, к которому применяется свойство border-radius и Flexbox могли бы быть отдельными статьями (второе требует гораздо более долгого объяснения), я оставлю эти темы на потом.

    Конечные результаты

    Как я упоминал ранее, написание кода для объектов SVG вручную может занимать много времени, особенно если принять во внимание тот факт, что существует множество прекрасных JavaScript библиотек, которые построят эти объекты за вас. Но могут быть случаи (как моя ситуация), где вам или вашей команде нужен метод, который не затрагивает JavaScript, тот, что будет собран на стороне сервера.

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

    Мои результаты:

    • Применять математику к чему-то вроде этого гораздо более интересно, чем в старшей школе.
    • Оглядываясь назад, я понимаю, что логика, стоящая за stroke-dasharray и stroke-dashoffset не такая сложная, как я думал изначально.
    • Не забудьте добавить сюда дополнительные уровни доступности. В конце концов, доступность нужна не только в угоду программам чтения с экрана. Она также нужна, чтобы сделать ваш контент более доступным и потребляемым всеми людьми и всеми устройствами (включая поисковые системы). Если ваша JavaScript-библиотека не имеет функций доступности, подумайте над ее изменением.

    Для front-end разработчика существует огромное количество способов, которыми можно построить круговую диаграмму -  разнообразные библиотеки, плагины, потрясающие возможности SVG графики и т.д. Однако стоит, пожалуй, рассмотреть и самый простой способ создания «пирожкового» чарта, который может быть полезен, когда задача поставлена максимально просто и нет необходимости или возможности использовать дополнительные инструменты. Далее речь пойдёт о примере такой реализации.

    Предположим, что имеются исходные данные в виде такого массива, которые нужно представить на круговой диаграмме:

    Var dataset = [ { value: 5, color: "#dc3912" }, { value: 40, color: "#ff9900" }, { value: 30, color: "#109618" }, { value: 25, color: "#990099" } ];

    value -  это значение в процентах, color -  цвет сектора.

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

    Зададим ему также стили:

    Container { width: 300px; height: 300px; overflow: hidden; border-radius: 50%; position: relative; }

    В результате получаем такой круг. Всё, что выходит за пределы его границ (изображены пунктиром) будет скрыто.

    Далее закономерно возникает вопрос -  как мы превратим прямоугольные элементы div в секторы круга и как зададим им нужный угол? Собственно, для первой цели и было установлено свойство overflow:hidden контейнеру, т.к. это позволяет скрыть часть элемента, сделав его таким образом округлым, а для второй нам помогут CSS-трансформации. Далее на примере для одного сектора.

    Добавим внутрь контейнера div с классом sector.

    CSS:

    Sector { width: 50%; height: 50%; position: absolute; left: 50%; top: 0; transform-origin: left bottom; background: #000; }

    Таким образом, получился сектор со значением 90 градусов, начинающийся на отметке в 0 градусов.

    Для того, чтобы задать нужный угол этому сектору, применим CSS-трансформацию skewY. Эта трансформация сдвигает правое ребро квадрата по оси y так, чтобы горизонтальные рёбра образовывали заданный угол со своим исходным положением:

    Значение value в первом элементе массива dataset равно 5, переводя в градусы, получаем 18. Для того, чтобы наклон происходил в нужную сторону, ко всем углам будем добавлять 90 градусов.

    Таким образом, угол трансформации = 90 + 18 = 108.

    transform: skewY(108deg);

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

    Transform: rotate(45deg) skewY(108deg);

    У этого способа есть один недостаток -  как видно на рисунке, иллюстрирующем значения трансформации skewY, таким образом можно корректно изображать сектора со значением не более 90 градусов. Поэтому для изображения значений, больших, чем 90, придётся рисовать несколько секторов одинакового цвета. Например, если значение угла 100 градусов, отобразим 2 сектора: 90 градусов и 10. Если значение равно 200 градусам, получится 3 сектора -  по 90, 90 и 20 градусов и т.д.

    В результате получаем следующий код для динамического добавления секторов:

    Var maxValue = 25; var container = $(".container"); var addSector = function(data, startAngle, collapse) { var sectorDeg = 3.6 * data.value; var skewDeg = 90 + sectorDeg; var rotateDeg = startAngle; if (collapse) { skewDeg++; } var sector = $("", { "class": "sector" }).css({ "background": data.color, "transform": "rotate(" + rotateDeg + "deg) skewY(" + skewDeg + "deg)" }); container.append(sector); return startAngle + sectorDeg; }; dataset.reduce(function (prev, curr) { return (function addPart(data, angle) { if (data.value