Без рубрики

Привлекательная анимированная круглая диаграмма

В данном уроке мы разберем, как построить привлекательную круговую диаграмму, которая обладает интерактивными функциями на основе HTML5. Еще недавно такие задачи можно было решать только с использованием Flash. Но теперь, благодаря появлению элемента HTML5 canvas мы можем создавать чудесные анимационные эффекты с использованием только javascript, CSS и математики!В данном уроке мы разберем, как построить привлекательную круговую диаграмму, которая обладает интерактивными функциями на основе HTML5. Еще недавно такие задачи можно было решать только с использованием Flash. Но теперь, благодаря появлению элемента HTML5 canvas мы можем создавать чудесные анимационные эффекты с использованием только javascript, CSS и математики!

Исходники

Прикреплённые файлы:
Файл: demo.zip
Размер: [9,04 Kb] (забрали: 15 раз)

Шаг 1. Создаем разметку

Вот разметка нашей демонстрационной страницы:

<!DOCTYPE html>
<html xmlns=»http://www.w3.org/1999/xhtml»>
<head>

<title>Привлекательная анимированная диаграмма | HTML5 и jQuery | Демонстрация для сайта RUSELLER.COM</title>
<meta http-equiv=»Content-Type» content=»text/html;charset=utf-8″ >

</head>
<body>

<div id=»container»>

  <div class=»wideBox»>
    <h1>Продажи штукуевин в 2010</h1>
    <p>Нажмите на цветном секторе в диаграмме или на строке в таблице, чтобы выдвинуть сектор!</a></p>
  </div>

  <canvas id=»chart» width=»600″ height=»500″></canvas>

  <table id=»chartData»>

    <tr>
      <th>Штукуевина</th><th>Продажи ($)</th>
     </tr>

    <tr style=»color: #0DA068″>
      <td>СуперШтука</td><td>1862.12</td>
    </tr>

    <tr style=»color: #194E9C»>
      <td>МегаШтука</td><td>1316.00</td>
    </tr>

    <tr style=»color: #ED9C13″>
      <td>ГиперШтука</td><td>712.49</td>
    </tr>

    <tr style=»color: #ED5713″>
      <td>ЧудоШтука</td><td>3236.27</td>
    </tr>

    <tr style=»color: #057249″>
      <td>МикроШтука</td><td>6122.06</td>
    </tr>

    <tr style=»color: #5F91DC»>
      <td>НаноШтука</td><td>128.11</td>
    </tr>

    <tr style=»color: #F88E5D»>
      <td>Модная Штука</td><td>245.55</td>
    </tr>
  </table>

</div>

</body>
</html>

Разметка очень простая. Она содержит:
div container, в котором размещен контент для центрирования на странице
Элемент HTML5 canvas для круговой диаграммы
Элемент table, который содержит данные для диаграммы
Заголовок страницы

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

Шаг 2. Создаем CSS

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

<style>

body {
  background: #fff;
  color: #333;
  font-family: «Trebuchet MS», Verdana, Arial, Helvetica, sans-serif;
  font-size: 0.9em;
  padding: 40px;
}

.wideBox {
  clear: both;
  text-align: center;
  margin-bottom: 50px;
  padding: 10px;
  background: #ebedf2;
  border: 1px solid #333;
  line-height: 80%;
}

#container {
  width: 900px;
  margin: 0 auto;
}

#chart, #chartData {
  border: 1px solid #333;
  background: #ebedf2 url(«images/gradient.png») repeat-x 0 0;
}

#chart {
  display: block;
  margin: 0 0 50px 0;
  float: left;
  cursor: pointer;
}

#chartData {
  width: 200px;
  margin: 0 40px 0 0;
  float: right;
  border-collapse: collapse;
  box-shadow: 0 0 1em rgba(0, 0, 0, 0.5);
  -moz-box-shadow: 0 0 1em rgba(0, 0, 0, 0.5);
  -webkit-box-shadow: 0 0 1em rgba(0, 0, 0, 0.5);
  background-position: 0 -100px;
}

#chartData th, #chartData td {
  padding: 0.5em;
  border: 1px dotted #666;
  text-align: left;
}

#chartData th {
  border-bottom: 2px solid #333;
  text-transform: uppercase;
}

#chartData td {
  cursor: pointer;
}

#chartData td.highlight {
  background: #e8e8e8;
}

#chartData tr:hover td {
  background: #f0f0f0;
}

</style>

Здесь тоже нет сюрпризов. CSS содержит правила для страницы, прямоугольников заголовка и нижнего колонтитула, контейнера, элементов #chart canvas и #chartData table.

Отметим пару моментов:
Элементы #chart и #chartData получают в качестве фона нежный градиент, создаваемый с помощью изображения gradient.png (оно входит в состав исходников). Да, для элемента canvas можно устанавливать изображения в качестве фона!
Мы используем свойство CSS3 box-shadow (и его эквиваленты для различных браузеров), чтобы установить тень для таблицы данных. (Хотя возможно добавить тень и для элемента canvas, но практика показала, что в этом случае анимация диаграммы существенно замедляется в браузерах WebKit.)

Шаг 3. Включаем jQuery и библиотеку ExplorerCanvas

Теперь можно приступать к написанию javascript кода. сначала включим две библиотеки:


<!—[if IE]>

jQuery не нуждается в представлении.

ExplorerCanvas. Internet Explorer, конечно же не поддерживает элемент canvas. К счастью, несколько отличных программистов создали ExplorerCanvas, библиотеку, которая эмулирует большинство методов и свойств элемента canvas с помощью возможностей IE SVG. Не все так хорошо, как хотелось бы, но для наших целей будет достаточно. Так как только IE нуждается в данной библиотеке, то мы используем условный комментарий для ее загрузки только в IE.

Обе библиотеки подгружаются с удаленных хранилищ, но вы можете скопировать их на локальный сервер и загружать с него.
Шаг 4. Создаем основную функцию, раздел конфигурации и полезные перменные

Мы заключим наш код в одну основную функцию pieChart(). Таким образом, все функции и переменные, относящиеся к диаграмме, будут сконцентрированны в одном месте и не будут загрязнять глобальное пространство имен. Для вызова функции pieChart() мы будем использовать jQuery после загрузки DOM.

Начнем с размещения переменных конфигурации в функции pieChart():


// Код выполняется когда DOM готова
$( pieChart );

function pieChart() {

  // Конфигурация
  var chartSizePercent = 55;                        // Радиус диаграммы, выраженный в процентах от размеров области рисования
  var sliceBorderWidth = 1;                         // Ширина (в пискселях) границы вокруг каждого сектора
  var sliceBorderStyle = «#fff»;                    // Цвет границы вокруг каждого сектора
  var sliceGradientColour = «#ddd»;                 // Цвет, который используется с одного конца диаграммы для создания градиента
  var maxPullOutDistance = 25;                      // Насколько далеко будет выдвигаться сектор из диаграммы
  var pullOutFrameStep = 4;                         // На сколько пикселей перемещается сектор в каждом кадре анимации
  var pullOutFrameInterval = 40;                    // Сколько ms проходит между кадрами
  var pullOutLabelPadding = 65;                     // Отступ между выдвинутым сектором и его меткой
  var pullOutLabelFont = «bold 16px ‘Trebuchet MS’, Verdana, sans-serif»;  // Шрифт метки выдвинутого сектора
  var pullOutValueFont = «bold 12px ‘Trebuchet MS’, Verdana, sans-serif»;  // Шрифт значения выдвинутого сектора
  var pullOutValuePrefix = «$»;                     // Префикс значения выдвинутого сектора
  var pullOutShadowColour = «rgba( 0, 0, 0, .5 )»;  // Цвет тени выдвинутого сектора
  var pullOutShadowOffsetX = 5;                     // Смещение по оси X (в пикселях) тени выдвинутого сектора
  var pullOutShadowOffsetY = 5;                     // Смещение по оси Y (в пикселях) тени выдвинутого сектора
  var pullOutShadowBlur = 5;                        // Насколько сильно размыта тень выдвинутого сектора
  var pullOutBorderWidth = 2;                       // Ширина (в пикселях) границы выдвинутого сектора
  var pullOutBorderStyle = «#333»;                  // Цвет границы выдвинутого сектора
  var chartStartAngle = -.5 * Math.PI;              // Начало диаграммы на 12 часов, а не на 3-х

  // Объявдение некоторых перменных для диаграммы
  var canvas;                       // Область рисования на странице
  var currentPullOutSlice = -1;     // Сектор, который выдвинут в текущий момент(-1 = нет выдвинутого сектора)
  var currentPullOutDistance = 0;   // На сколько пикселей смещен текущий выдвигаемый сектор в ходе анимации
  var animationId = 0;              // ID интервала анимации, созданный с помощью setInterval()
  var chartData = [];               // Данные диаграммы (метки, значения, углы)
  var chartColours = [];            // Цвета диаграммы (получены из таблицы HTML)
  var totalValue = 0;               // Сумма всех значений в диаграмме
  var canvasWidth;                  // Ширина области рисования
  var canvasHeight;                 // Высота области рисования
  var centreX;                      // Координата X центра диаграммы на области рисования
  var centreY;                      // Координата Y центра диаграммы на области рисования
  var chartRadius;                  // Радиус диаграммы в пикселях

  // Инициализируем данные и рисуем диаграмму
  init();

Большинство из этих строк имеют очевидное значение в соответствии с комментарием. Несколько важных переменных разберем более тщательно:


chartSizePercent
Для того, чтобы выдвигать сектор и выводить метку для него нужно иметь достаточно пространства. Реальный размер диаграммы будет меньше, чем область рисования. В нашем случае 55% является достаточной величиной.



chartStartAngle
По умолчанию углы в javascript, как и в большинстве языков программирования, задаются в радианах, при этом 0 радиан соответствует положению на 3 часа.Так как мы хотим начать отсчет с 12 часов, нужно установить смещение на /2 радиан (четверть круга) для всех углов в коде. На рисунке ниже приводится подробное объяснение.

currentPullOutSlice и currentPullOutDistance
Так как мы планируем анимировать выдвижение сектора из диаграммы, то данные переменные нужны для отслеживания анимации. currentPullOutSlice содержат указание на то, какой сектор выдвигается из диаграммы (величина -1 означает, что никакой сектор из диаграммы не выдвинут), а currentPullOutDistance задает дистанцию, на которую выдвигается сектор.

animationId
Данная переменная содержит значение, которое возвращает функция setInterval(), когда мы создаем анимацию. Это числовой идентификатор, который мы можем передавать функции clearInterval(), когда надо завершать анимацию.

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

chartColours
Массив, который содержит цвета для секторов. Значения также получаются из таблицы HTML.

init()
Вызывает функцию init(), которая устанавливает диаграмму и запускает остальные процессы.

Шаг 5. Инициализируем диаграмму

Теперь мы готовы вывести диаграмму. Давайте разберем функцию init():

/**
* Устанавливаем для диаграммы данные и цвета, а также устанавливаем обработчики события click
* для диаграммы и таблицы. Рисуем диаграмму.
*/

function init() {

  // Получаем область рисования на странице
  canvas = document.getElementById(‘chart’);

  // Выходим, если браузер не имеет возможности рисовать
  if ( typeof canvas.getContext === ‘undefined’ ) return;

  // Инициализуем некоторые свойства области рисования и диаграммы
  canvasWidth = canvas.width;
  canvasHeight = canvas.height;
  centreX = canvasWidth / 2;
  centreY = canvasHeight / 2;
  chartRadius = Math.min( canvasWidth, canvasHeight ) / 2 * ( chartSizePercent / 100 );

  // Получаем данные из таблицы
  // и устанавливаем обработчики события click для ячеек таблицы
  
  var currentRow = -1;
  var currentCell = 0;

  $(‘#chartData td’).each( function() {
    currentCell++;
    if ( currentCell % 2 != 0 ) {
      currentRow++;
      chartData[currentRow] = [];
      chartData[currentRow][‘label’] = $(this).text();
    } else {
     var value = parseFloat($(this).text());
     totalValue += value;
     value = value.toFixed(2);
     chartData[currentRow][‘value’] = value;
    }

    // Сохраняем индекс сектора в ячейке и привязываем к ней обработчик события click
    $(this).data( ‘slice’, currentRow );
    $(this).click( handleTableClick );

    // Получаем и сохраняем цвет ячейки
    if ( rgb = $(this).css(‘color’).match( /rgb((d+), (d+), (d+)/) ) {
      chartColours[currentRow] = [ rgb[1], rgb[2], rgb[3] ];
    } else if ( hex = $(this).css(‘color’).match(/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/) ) {
      chartColours[currentRow] = [ parseInt(hex[1],16) ,parseInt(hex[2],16), parseInt(hex[3], 16) ];
    } else {
      alert( «Ошибка: Цвет не может быть определен! Пожалуйста, задайте таблицу цветов в формате ‘#xxxxxx'» );
      return;
    }

  } );

  // Теперь вычисляем и сохраняем начальный и конечный угол каждого сектора в диаграмме

  var currentPos = 0; // Текущая позиция сектора (от 0 до 1)

  for ( var slice in chartData ) {
    chartData[slice][‘startAngle’] = 2 * Math.PI * currentPos;
    chartData[slice][‘endAngle’] = 2 * Math.PI * ( currentPos + ( chartData[slice][‘value’] / totalValue ) );