Делаем динамическую гистограмму с использованием JS и jQuery

14.01.2017

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

Пример реализации ниже:

5
4
3
2
1

Вариант 1 — Простой JS

 

Используем такой html:

<div class="rating-histogram">
  <div class="rating-bar-container five">
    <span class="bar-label"> 5 </span>
    <span class="bar"></span> 
    <span class="bar-number"></span> 
  </div>
  <div class="rating-bar-container four">
    <span class="bar-label"> 4 </span>
    <span class="bar"></span> 
    <span class="bar-number"></span>  
  </div>
  <div class="rating-bar-container three">
    <span class="bar-label"> 3 </span>
    <span class="bar"></span> 
    <span class="bar-number"></span> 
  </div>
  <div class="rating-bar-container two">
    <span class="bar-label"> 2 </span>
    <span class="bar"></span> 
    <span class="bar-number"></span>  
  </div>
  <div class="rating-bar-container one">
    <span class="bar-label"> 1 </span>
    <span class="bar"></span> 
    <span class="bar-number"></span> 
  </div>
</div><!-- /rating-histogram -->

<div class="hidden"><!-- needs for jquery calculations -->
  <form>
    <input type="text" class="reviews_1star" value="5">
    <input type="text" class="reviews_2star" value="4">
    <input type="text" class="reviews_3star" value="2">
    <input type="text" class="reviews_4star" value="6">
    <input type="text" class="reviews_5star" value="3">
  </form>
</div><!-- /hidden -->

В блоке div.hidden мы выводим количество голосов за каждую оценку, например,
1 балл — 5 голосов,
2 балла — 4 голоса,
3 балла — 2 голоса,
4 балла — 6 голосов,
5 баллов — 3 голоса.
Для WordPress мы можем эти оценки выводить через кастомные поля <?php the_field('reviews_1star'); ?> и т.д., а в HTML это могут быть статические данные, но они обязательно должны быть, потому что используются для подсчета и построения гистограммы.

Используем такой JS:

<script>
  $(function() {

    var reviews_1star = parseInt($('.reviews_1star').val());
    var reviews_2star = parseInt($('.reviews_2star').val());
    var reviews_3star = parseInt($('.reviews_3star').val());
    var reviews_4star = parseInt($('.reviews_4star').val());
    var reviews_5star = parseInt($('.reviews_5star').val());

    var sum = reviews_1star + reviews_2star + reviews_3star + reviews_4star + reviews_5star;

    var width_1star = (reviews_1star / sum * 100).toFixed(0);
    var width_2star = (reviews_2star / sum * 100).toFixed(0);
    var width_3star = (reviews_3star / sum * 100).toFixed(0);
    var width_4star = (reviews_4star / sum * 100).toFixed(0);
    var width_5star = (reviews_5star / sum * 100).toFixed(0);

    $('.rating-bar-container.one .bar').css('width', width_1star+'%' );
    $('.rating-bar-container.two .bar').css('width', width_2star+'%' )
    $('.rating-bar-container.three .bar').css('width', width_3star+'%' );
    $('.rating-bar-container.four .bar').css('width', width_4star+'%' );
    $('.rating-bar-container.five .bar').css('width', width_5star+'%' );

    if (sum > 0) {
      $(".rating-bar-container.one .bar-number").html(width_1star+'%');
      $(".rating-bar-container.two .bar-number").html(width_2star+'%');
      $(".rating-bar-container.three .bar-number").html(width_3star+'%');
      $(".rating-bar-container.four .bar-number").html(width_4star+'%');
      $(".rating-bar-container.five .bar-number").html(width_5star+'%');
    } else{
      $(".rating-bar-container .bar-number").html('0%')
    }

  });
</script>

В head подключаем jquery, если он не подключен:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>

Используем Такой CSS:

<style>
  .rating-histogram {
    padding: 5px 5px 5px 44px;
    text-align: left; 
    width: 100%;
  }
  .rating-histogram .rating-bar-container {
    position: relative;
    margin-bottom: 5px; 
  }
  .rating-histogram .bar-label {
    margin-right: 10px;
    position: absolute;
    left: -44px;
    top: 2px; 
  }
  .rating-histogram .bar-label:before {
    content: "\f005";
    font-family: FontAwesome;
    font-size: 16px;
    line-height: 16px;
    height: 16px;
    width: 16px;
    color: #ccc;
    display: inline-block;
    margin-right: 5px; 
  }
  .rating-histogram .bar {
    background-color: #8e70af;
    background-image: -webkit-linear-gradient(left, #8e70af, #48bfed);
    background-image: linear-gradient(to right,#8e70af, #48bfed);
    -webkit-transition: width 2s ease;
    -moz-transition: width 2s ease;
    transition: width 2s ease;
    opacity: .8;
    display: inline-block;
    vertical-align: middle;
    width: 1%;
    height: 15px;
    margin-right: 3px; 
  }
  .rating-histogram .bar-number {
    font-size: 14px;
    line-height: 1;
    vertical-align: middle; 
  }
  .hidden{
    display: none;
  }
</style>

В CSS используется шрифт иконок FontAwesome, он у вас должен быть подключен.

 

Вариант 2 — Более профессиональный, оптимизирован JS

 

Меняем HTML на такой формат:

<div class="rating-histogram">
  <div class="rating-bar-container five" data-id="5">
    <span class="bar-label"> 5 </span>
    <span class="bar"></span> 
    <span class="bar-number"></span> 
  </div>
  <div class="rating-bar-container four" data-id="4">
    <span class="bar-label"> 4 </span>
    <span class="bar"></span> 
    <span class="bar-number"></span>  
  </div>
  <div class="rating-bar-container three" data-id="3">
    <span class="bar-label"> 3 </span>
    <span class="bar"></span> 
    <span class="bar-number"></span> 
  </div>
  <div class="rating-bar-container two" data-id="2">
    <span class="bar-label"> 2 </span>
    <span class="bar"></span> 
    <span class="bar-number"></span>  
  </div>
  <div class="rating-bar-container one" data-id="1">
    <span class="bar-label"> 1 </span>
    <span class="bar"></span> 
    <span class="bar-number"></span> 
  </div>
</div><!-- /rating-histogram -->

<div class="hidden"><!-- needs for jquery calculations -->
  <form>
    <input type="text" class="reviews_1star" value="5">
    <input type="text" class="reviews_2star" value="4">
    <input type="text" class="reviews_3star" value="2">
    <input type="text" class="reviews_4star" value="6">
    <input type="text" class="reviews_5star" value="3">
  </form>
</div><!-- /hidden -->

Добавился только параметр data-id для div.rating-bar-container

А JS меняем на такой оптимизированный код:

<script>
  $(function() {
    var stars = new Array();
    var sum = 0;
    var width = new Array();
    
    for ( var i = 1; i < 6; i++ ) {
      stars.push(parseInt($('.reviews_'+i+'star').val()));
    }      
    
    for ( var i = 0; i < stars.length; i++ ) {
      sum += stars[i];        
    }      
    
    for ( var i = 0; i < stars.length; i++ ) {
      w = ((stars[i]) / sum * 100).toFixed(0);
      width.push(w);
      $('.rating-bar-container[data-id='+(i+1)+'] .bar').css('width', w+'%' );  
    }

    if (sum > 0) {
      for ( var i = 0; i < stars.length; i++ ) {
        $('.rating-bar-container[data-id='+(i+1)+'] .bar-number').html(width[i]+'%');  
      }
    } else{
      $(".rating-bar-container .bar-number").html('0%')
    }
  });
</script>

CSS остается прежним.

Код на CodePen

See the Pen Animated Rating Histogram by Denis (@deniscreative) on CodePen.

За помощь спасибо Algiz.

Полезная инфа:

Оставить комментарий