0

I am trying to build a horizontal calendar timeline using d3.js. Main goal is to highlight holidays and vacations of user.

http://jsbin.com/ceperavu/2/edit?css,js,output

  • I first rect from 'start' date to 'end' date.
  • Then append text.
  • highlight the rect which match the data from vacations
  • but it highlights always the first 'n' rect.

    var width = 650;
    var height = 450;
    var date = {start: '02/24/2014', end: '03/17/2014'};
    var day = d3.time.format("%d");
    var vacations = ['02/25/2014', '02/28/2014', '03/05/2014', '03/14/2014'];
    var cell = {width: 20, height: 20};
    var format = d3.time.format("%m/%d/%Y");
    
    var chart = d3.select("body")
                  .append('svg:svg')
                  .attr('width', width)
                  .attr('height', height)
                  .attr('class', 'chart');
    
    
    
    var days = chart
        .selectAll(".day")
        .data(function(d) { return d3.time.days(new Date(date.start), new Date(date.end)); })
        .enter()
        .append('svg:g');
    
    //add rect
        days.append('svg:rect')
          .attr('width', cell.width)
          .attr('height', cell.height)
          .attr('x', function(d, i){ 
            var day = d3.time.format("%d"); 
            // console.log(day(d)); 
            return i * cell.width; })
          .attr('class', 'day')
          .append('title')
            .text(function(d){return format(d);})
          .datum(format);
    
    //add text
        days.append('svg:text')
          .attr('width', cell.width)
          .attr('height', cell.height)
          .attr('x', function(d, i){
            return i * cell.width + cell.width/4; 
          })
          .attr('y', 14)
          // .style('text-anchor', 'middle')
          // .style('dominant-baseline', 'central')
          .text( function(d) { var day = d3.time.format("%d");return day(d); });
    
    //highlight holidays
    d3.selectAll('rect.day').data(vacations).attr('class', 'holiday');
    

Is this wrong d3.selectAll('rect.day').data(vacations).attr('class', 'holiday'); ?

Edit: format and additional details.

2 Answers 2

3

I have changed the input data a bit so that you can compare apples to apples and also used a helper function from jquery. This fiddle is the result. Hope this helps.

days.selectAll('rect.day')
    .attr('class', function (d) {
        return  ($.inArray(d.getTime(), vacations))  > -1 ? 'holiday' : 'day';
    });
Sign up to request clarification or add additional context in comments.

7 Comments

To clarify: The original code was replacing the data about the dates with data about vacations; without a key function, the new data was just being assigned from the beginning. @FernOfTheAndes' code grabs all the rectangles and styles them if their date matches a vacation day. You could alternately use a d3 filter instead of doing the check within the attribute method call, but the end effect would be the same. Filters are preferred if you're going to set multiple attributes or styles based on the same filter criteria.
Also, if you don't already have JQuery on your page, you can use vacations.indexOf[d.getTime] > -1. It doesn't work in IE8, but neither does your SVG graphics.
For comparison, the fiddle using filter format: jsfiddle.net/3FrsG/1, and using the standard Javascript method instead of JQuery: jsfiddle.net/3FrsG/2
@UnknownUser First, I made a few typos, it should be round brackets like (), not hard brackets [], and there should also be () after getTime. The .indexOf method (and also the JQuery method from the main post) looks through an array for an entry that is equals (===) to the value you pass in (d.getTime). If it finds a match, it returns the index of the first match, which will be a number 0 or greater. If it doesn't find a match, it returns -1. So vacations.indexOf(d.getTime()) > -1 returns true if the array vacations contains a match for d.getTime().
I should mention that it only works because the vacations array has been modified to contain timestamp values that will match the results of getTime(). @FernOfTheAndes's code does this in the original data array, but you could also use a map function: var vacationsAsTimestamp = vacations.map(function(dateString){ return new Date(dateString).getTime();} ); Live version
|
-1

Here's the Fiddle.

Problem was with this code near the days variable.

var days = chart.selectAll(".day")
    .data(function(d) { return d3.time.days(new Date(date.start), new Date(date.end)); })
        .enter()
        .append('svg:g')
    .attr('class', 'day');

Earlier it was like this.

var days = chart
.selectAll(".day")
    .data(function(d) { return d3.time.days(new Date(date.start), new Date(date.end)); })
        .enter()
        .append('svg:g')
    .attr('class', 'day');

Please check if it helps.

3 Comments

I don't see any change except for newline remove on first line. I does not solve the main issue of highlighting dates listed vacations variable
You wanted to highlight the vacation days?
Yes. I want to highlight the vacation days.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.