Dheeraj
Dheeraj

Reputation: 556

Alternating tick padding in d3.js

I am writing the following d3.js function for brush. This function works fine for me but i want to alternate the tick padding for the brush so that two consecutive ticks are not on the same height and hence do not overlap. This maintains the clarity of the ticks. Can anyone suggest the right way to do so in the following function.

$scope.drawBrush = function (span) {

    var width = 400,
        height = 50;

    var x = d3.time.scale()
        .domain([new Date($scope.range1), new Date($scope.range2)])
        .range([0, width]);
    d3.select('#brushd').remove();
    var brush = d3.svg.brush()
        .x(x)
        .extent([new Date($scope.range1), new Date($scope.range2)])
        .on('brush', brushed);
    var svg = d3.select('#brush-div').append('svg')
        .attr('id', 'brushd')
        .attr('width', '400')
        .attr('height', '80')
        .style('margin-left', '0px')
        .append('g')
        .attr('transform', 'translate(' + 50 + ',' + 0 + ')');

    svg.append('rect')
        .attr('class', 'grid-background')
        .attr('width', width)
        .attr('height', height);

    svg.append('g')
        .attr('class', 'x grid')
        .attr('transform', 'translate(0,' + height + ')')
        .call(d3.svg.axis()
            .scale(x)
            .orient('bottom')
            .ticks(d3.time.hours, 12)
            .tickSize(-height)
            .tickFormat(''))
        .selectAll('.tick')
        .classed('minor', function (d) {
            return d.getHours();
        });

    svg.append('g')
        .attr('class', 'x axis')
        .attr('transform', 'translate(0,' + height + ')')
        .call(d3.svg.axis()
            .scale(x)
            .orient('bottom')
            .tickFormat(d3.time.format('%b-%y'))
            .tickPadding(0))
        .selectAll('text')
        .attr('x', 6)
        .style('text-anchor', null);

    var gBrush = svg.append('g')
        .attr('class', 'brush')
        .call(brush);

    gBrush.selectAll('rect')
        .attr('height', height);

    function brushed() {
        var extent0 = brush.extent(),
            extent1;
        // if dragging, preserve the width of the extent
        if (d3.event.mode === 'move') {
            var d0 = d3.time.day.round(extent0[0]),
                d1 = d3.time.day.offset(d0, Math.round((extent0[1] - extent0[0]) / 864e5));
            extent1 = [d0, d1];
        }

        // otherwise, if resizing, round both dates
        else {
            if (span === 'daily') {
                extent1 = extent0.map(d3.time.day.round);

                // if empty when rounded, use floor & ceil instead
                if (extent1[0] >= extent1[1]) {
                    extent1[0] = d3.time.day.floor(extent0[0]);
                    extent1[1] = d3.time.day.ceil(extent0[1]);
                }
            } else if (span === 'weekly') {
                extent1 = extent0.map(d3.time.week.round);

                // if empty when rounded, use floor & ceil instead
                if (extent1[0] >= extent1[1]) {
                    extent1[0] = d3.time.week.floor(extent0[0]);
                    extent1[1] = d3.time.week.ceil(extent0[1]);
                }
            } else {
                extent1 = extent0.map(d3.time.month.round);

                // if empty when rounded, use floor & ceil instead
                if (extent1[0] >= extent1[1]) {
                    extent1[0] = d3.time.month.floor(extent0[0]);
                    extent1[1] = d3.time.month.ceil(extent0[1]);
                }
            }
        }
        d3.select(this).call(brush.extent(extent1));
        $scope.getLimit(brush.extent()[0], brush.extent()[1]);

    }
};

Upvotes: 3

Views: 5457

Answers (2)

user1146300
user1146300

Reputation: 279

Try this for tick labeling.

    // Alternate the tick label text to match up with the tick length
    d3.selectAll("g.x.axis g.tick text")
        .each(function (d, i) {
            //console.log(i % 2);
            if ((i % 2)) {  //even
                this.remove();
            }
    });

Upvotes: 3

Henry S
Henry S

Reputation: 3112

One way to alternate between long and short ticks on your x-axis, to achieve this sort of thing:

enter image description here

... is like this:

// flag to alternate between long and short ticks
var alternate_ticks = false;

var short_tick_length = 4;
var long_tick_length = 16;

// Alternate the tick line between long and short ticks
d3.selectAll("g.x.axis g.tick line")
    .attr("y2", function () {
        if (alternate_ticks) {
            alternate_ticks = false;
            return long_tick_length;
        } else {
            alternate_ticks = true;
            return short_tick_length;
        }
    });

var alternate_text = false;

// Alternate the tick label text to match up with the tick length
d3.selectAll("g.x.axis g.tick text")
    .attr("y", function () {
            if (alternate_text) {
                alternate_text = false;
                return long_tick_length + 1;
            } else {
                alternate_text = true;
                return short_tick_length + 1;
            }
    });

It's a simpler version of the same approach as Lars K pointed out above, but using a simpler function that just alternates between false and true to determine tick length and text positioning on the relevant set of objects.

Upvotes: 4

Related Questions