JSFiddle - React, Tailwind, and code Playground

by kontrach

HTML

<script src="//d3js.org/d3.v4.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Detailed timeline</title>

    <script src="//d3js.org/d3.v4.min.js"></script>
    <link rel="stylesheet" href="style.css">
</head>
<body>

<div id="navigation"></div>

<script src="script1.js"></script>

</body>
</html>

CSS

#navigation {
    display: flex;
}

#navigation svg {
    border-top: 1px solid #DADADA;
    border-bottom: 1px solid #DADADA;
}

.circle {
    fill: #F5A623;
}

.overlay {
    cursor: default;
}

.domain {
    /*stroke: #fff;*/
    opacity: 0;
}

.selected {
    fill: #ff00d0;
    fill-opacity: 1;
}

.selection {
    fill: #f2f9fd;
    fill-opacity: 0.8;

    /*stroke-dasharray: 50, 150, 50;*/
    /*stroke: #005B92;*/
}

.button {
    width: 24px;
    background-color: #005B92;
    color: #fff;
    border: none;
}

JavaScript

const data = [{
    date: '2017-01-21'
}, {
    date: '2017-04-01'
}, {
    date: '2017-05-21'
}, {
    date: '2017-12-12'
}];

const buttonWidth = 24;

const container = d3.select("#navigation");
const leftButton = container.append('button')
    .text("<")
    .attr("class", 'button')
    .on("click", () => handleClick("left"));
const svg = container.append("svg")
    .attr("width", 800 - 2 * buttonWidth)
    .attr("wmode", "Transparent")
    .attr("height", 64);
const rightButton = container.append('button')
    .text(">")
    .attr("class", 'button')
    .on("click", () => handleClick("right"));

const margin = {top: 0, right: 10, bottom: 20, left: 10};
const width = +svg.attr("width");
const height = +svg.attr("height");

const group = svg.append("g");

// Create scale
const x = d3.scaleTime()
    .domain([new Date(data[0].date), new Date(data[data.length - 1].date)])
    .range([margin.left, width - margin.right]);

// Add axis
const axisGroup = group.append("g");
axisGroup
    .attr("class", "axis")
    .attr("transform", "translate(0," + (height - margin.bottom) + ")")
    .call(d3.axisBottom(x).tickFormat(d3.timeFormat("%b")));

// Add dots
const dotsGroup = group.append("g")
    .attr("fill-opacity", 1)
    .selectAll("circle")
    .data(data)
    .enter().append("circle")
    .attr("class", "circle")
    .attr("transform", function(d) {
        return "translate(" + x(new Date(d.date)) + "," + 30 + ")";
    })
    .attr("r", 2);

// Add brush
const brush = d3.brushX()
    .extent([
        [0, 0],
        [width, height]
    ]);
brush.on("brush", function () {
    const extent = d3.event.selection.map(x.invert, x);
    dotsGroup.classed("selected", function(d) {
        const date = new Date(d.date);
        return extent[0] <= date && date <= extent[1];
    });
});

const brushGroup = group.append("g");
brushGroup
    .attr("class", "brush")
    .call(brush)
    .call(brush.move, [new Date(data[data.length - 3].date), new Date(data[data.length -...