Back to Blog

D3.js - krok po kroku. Eventy.

01 May 2016

Poprzednim razem dokończyłem statyczną wersję wykresu, gwoli przypomnienia, można go obejrzeć tutaj. Czymże jednak byłby graf w D3 bez interakcji. Pora więc wykorzystać potencjał eventów i tchnąć w niego życie.

Na wykresie wyświetlane są ilości projektów według ich rodzaju. Nazwa kategorii jest bardzo ogólna i można ją różnie zinterpretować. Na przykład, co dokładnie oznacza kategoria “Data”? W jednym z postów opisałem krótko każdą z nich, ale dobrze byłoby mieć tę informację również na wykresie. Żeby jednak nie przeładować zbytnio całości już na wstępie, początkowo opis kategorii będzie ukryty i pojawi się dopiero po najechaniu kursorem na belkę.

Na początek sprawmy, aby prostokąt, na którym znajduje się kursor, otrzymał trochę ciemniejszy kolor, co podkreśli jego zaznaczenie. Aby podpiąć obsługę danego zdarzenia do elementów selection, należy użyć funkcji on() przekazując jego nazwę oraz handler:

var bars = chart
    .selectAll('g')
    .data(categories)
    .enter()
    .append('g')
    .on('mouseover', function(d,i){
    })

Podobnie jak dla funkcji attr() czy style(), w handlerze zdarzenia mamy dostęp do powiązanego elementu danych (d) oraz jego indeks (i). Chwilowo nie będzie to jednak potrzebne, za to przydałby się aktualny znaznik, na który użytkownik najechał kursorem, aby móc zmienić jego kolor. Dobierzemy się do niego poprzez this, który wskazuje na element DOM będący źródłem zdarzenia:

.on('mouseover', function(){                
  d3.select(this).select('rect').style('fill', '#3182bd')
})

Jak widać d3.select() jest w stanie przyjąć nie tylko selektor CSS, ale również istniejący tag SVG. Każdy, kto zna jQuery poczuje się tu jak w domu. Brakuje jeszcze tego, aby przywrócić początkowy kolor po “wyjechaniu” kursora poza belkę:

.on('mouseout', function(d){
  d3.select(this).select('rect').style('fill', options.bar.color)  
});

Opisy poszczególnych kategorii dodałem jako nową kolumnę do pliku CSV. Tekst z opisem powinien pojawić się w prawym dolnym rogu. W tym celu, zamiast używać elementów SVG, dodałem standardowy span, dzięki któremu łatwiej zapanować nad właściwym wyrównaniem tekstu:

<body>
    <div id='description'>
        <span></span>
    </div>
    <svg id='container' >
    </svg>    
</body>
#description {       
   position: fixed;
}
#description > span{
   display: block;                        
   text-align: right;         
   position: absolute;
   bottom: 0;
   right: 0;   
   color: #555
}  

Nie zagłębiając się w szczegóły stylowania, odpowiednia zmiana position pozwala na nałożenie tekstu na kontener SVG. Jego dokładne koordynaty ustawiamy w skrypcie bazując na ustawieniach całego wykresu:

var descriptionWidth = 150;
d3.select('#description')
  .style('width',descriptionWidth)
  .style('left', options.width - descriptionWidth)
  .style('height',options.height - options.margin.bottom)

Pozostaje ustawić tekst elementu jako opis kategorii, po najechaniu kursorem na belkę:

var bars = chart
    .selectAll('g')
    //etc...
    .on('mouseover', function(d){                
     d3.select(this).select('rect').style('fill', '#3182bd')
     d3.select('#description').select('span').text(d.description)
    })
    .on('mouseout', function(d){
      d3.select(this).select('rect').style('fill', options.bar.color)
      d3.select('#description').select('span').text('')
    });

Efektu końcowy można zobaczyć tutaj. Pełny kod przykładu znajduje się w branchu categories-chart-3.