kwoxer
kwoxer

Reputation: 3833

Timeline just with years that shall be ordered and just showing per year how many values are available

I would like to use a timeline that just shows years. The special about my data is that I just have years. But these years are ordered. So I know the exact order but not any more detail like day or month.

So first of all I would like to have something like this:

enter image description here

This is when the years just have one event. But having many events should look like this one:

enter image description here

So what would be a good way to get this. I already had a look on the timeline of d3, but I have never seen just years where just the order is known.

Btw: later on I will need month and days because for some years I actually have them. But for 99,9% I do not. So the years are more important for now =)

Btw2: I also need to zoom in, the range is 0 until year 2500 round about.

Some links:

Small jsfiddle scetch

jsfiddle.net/kwoxer/z614xkgu/

Nearly what I'm looking for

http://visjs.org/examples/timeline/29_hiding_times.html

Just that the items shall also be zoomed in.

Upvotes: 0

Views: 1432

Answers (1)

Rob Schmuecker
Rob Schmuecker

Reputation: 8954

Here is an augmentation of your JS fiddle, Demo: http://jsfiddle.net/robschmuecker/c8txLxo9/

It takes the data you have and then parses it to get a collection of years so that we only insert one dom element per year rather than several. Then we can conditionally add events for years which have more than one. It has an axis based on the dates too and is zoomable.

var dataset = [
    ["2006", 1],
    ["2009", 1],
    ["2004", 1],
    ["2004", 2],
    ["2004", 3],
    ["2012", 1],
    ["2008", 1],
    ["2004", 2],
    ["2000", 1],
    ["2006", 2],
    ["2007", 1],
    ["2001", 1]
];

//console.log(dataset, dataset.length);

var yearEvents = [];

// Firstly get all the events together for each year in the dataset
dataset.forEach(function (value) {
    var yearString = value[0] + "";
    if (typeof yearEvents[yearString] == 'undefined') yearEvents[yearString] = [];
    yearEvents[yearString].push(value[1]);
});

var newDataset = [];
yearEvents.forEach(function (year, key) {
    newDataset.push([key + "", year]);
});
//console.log('yearEvents', newDataset);

var w = 500;
var h = 300;
var padding = 20;
var circleRadius = 10;

var parseDate = d3.time.format("%Y").parse;
var mindate = parseDate("2000"),
    maxdate = parseDate("2015");

var xScale = d3.time.scale()
    .domain([mindate, maxdate])
    .range([padding, w - padding * 2]);

var yScale = d3.scale.linear()
    .domain([0, d3.max(dataset, function (d) {
    return d[1];
})])
    .range([5, 5]);

// Define the axis
var xAxis = d3.svg.axis().scale(xScale).tickSize(-h).tickSubdivide(true);


// Define the zoom function for the zoomable tree

function zoom() {
    svgGroup.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
// define the zoomListener which calls the zoom function on the "zoom" event constrained within the scaleExtents
var zoomListener = d3.behavior.zoom().scaleExtent([0.1, 3]).on("zoom", zoom);



var svg = d3.select("body")
    .append("svg")
    .attr("width", w)
    .attr("height", h)
    .call(zoomListener);


// Append a group which holds all nodes and which the zoom Listener can act upon.
var svgGroup = svg.append("g");
svgGroup.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + (h - padding) + ")")
    .call(xAxis);

var circleGroups = svgGroup.selectAll('g.circle')
    .data(newDataset)
    .enter()
    .append('g')
    .attr("transform", function (d) {
    return "translate(" + xScale(parseDate(d[0])) + "," + (h - padding - (circleRadius * 3)) + ")";
});

var circles = circleGroups.append("circle").attr("r", circleRadius);


// Append the year value to the circles.  change `display` property to `block` in CSS to show them.
var circleTexts = circleGroups.append('text')
    .attr("class", "circle-year")
//make their horizontal position offest by half of their font-size.
.attr("dy", function () {
    return "0.25em"
})
    .attr("text-anchor", "middle")
    .text(function (d) {
    return d[0];
});

// Now add text to the ones with more than one event
circleGroups.each(function (d, i) {
    //console.log(this, d, i);
    var me = this;
    //see if it has more than one event and if so loop through them all and add the new text elements with their height separation based on their index
    if (d[1].length > 1) {
        d[1].forEach(function (event, index) {
            d3.select(me).append('text')
                .attr("dy", function () {
                return -((circleRadius * index) * 2 + padding);
            })
                .attr("text-anchor", "middle")
                .text(function (d) {
                return event;
            });
        });
    }
});

Upvotes: 1

Related Questions