From Dec 31 to May 01Use left and right arrows to move selectionFrom Dec 31Use left and right arrows to move left selectionTo May 01Use left and right arrows to move right selectionUse TAB to select grip buttons or left and right arrows to change selection100%Chart created using amCharts library
  • Open in:

Horizontal Serpentine chart

This demo uses amCharts 4 TimeLine add-on.

Add-on docs

Demo source

<!-- Styles -->
<style>
#chartdiv {
  width: 100%;
  height: 600px;
}

.demo-theme-dark .demo-background {
  background: #000;
}

</style>

<!-- Resources -->
<script src="https://cdn.amcharts.com/lib/4/core.js"></script>
<script src="https://cdn.amcharts.com/lib/4/charts.js"></script>
<script src="https://cdn.amcharts.com/lib/4/plugins/timeline.js"></script>
<script src="https://cdn.amcharts.com/lib/4/plugins/bullets.js"></script>
<script src="https://cdn.amcharts.com/lib/4/themes/animated.js"></script>

<!-- Chart code -->
<script>
am4core.ready(function() {

// Themes begin
am4core.useTheme(am4themes_animated);
// Themes end

var chart = am4core.create("chartdiv", am4plugins_timeline.SerpentineChart);
chart.curveContainer.padding(20,20,20,20);
chart.levelCount = 8;
chart.orientation = "horizontal";
chart.fontSize = 11;

var colorSet = new am4core.ColorSet();
colorSet.saturation = 0.6;

chart.data = [ {
  "category": "Module #1",
  "start": "2016-01-10",
  "end": "2016-01-13",
  "color": colorSet.getIndex(0),
  "task": "Gathering requirements"
}, {
  "category": "Module #1",
  "start": "2016-02-05",
  "end": "2016-04-18",
  "color": colorSet.getIndex(0),
  "task": "Development"
}, {
  "category": "Module #2",
  "start": "2016-01-08",
  "end": "2016-01-10",
  "color": colorSet.getIndex(5),
  "task": "Gathering requirements"
}, {
  "category": "Module #2",
  "start": "2016-01-12",
  "end": "2016-01-15",
  "color": colorSet.getIndex(5),
  "task": "Producing specifications"
}, {
  "category": "Module #2",
  "start": "2016-01-16",
  "end": "2016-02-05",
  "color": colorSet.getIndex(5),
  "task": "Development"
}, {
  "category": "Module #2",
  "start": "2016-02-10",
  "end": "2016-02-18",
  "color": colorSet.getIndex(5),
  "task": "Testing and QA"
}, {
  "category": "",
  "task": ""
},{
  "category": "Module #3",
  "start": "2016-01-01",
  "end": "2016-01-19",
  "color": colorSet.getIndex(9),
  "task": "Gathering requirements"
}, {
  "category": "Module #3",
  "start": "2016-02-01",
  "end": "2016-02-10",
  "color": colorSet.getIndex(9),
  "task": "Producing specifications"
}, {
  "category": "Module #3",
  "start": "2016-03-10",
  "end": "2016-04-15",
  "color": colorSet.getIndex(9),
  "task": "Development"
}, {
  "category": "Module #3",
  "start": "2016-04-20",
  "end": "2016-04-30",
  "color": colorSet.getIndex(9),
  "task": "Testing and QA"
}, {
  "category": "Module #4",
  "start": "2016-01-15",
  "end": "2016-02-12",
  "color": colorSet.getIndex(15),
  "task": "Gathering requirements"
},{
  "category": "Module #4",
  "start": "2016-02-25",
  "end": "2016-03-10",
  "color": colorSet.getIndex(15),
  "task": "Development"
}, {
  "category": "Module #4",
  "start": "2016-03-23",
  "end": "2016-04-29",
  "color": colorSet.getIndex(15),
  "task": "Testing and QA"
} ];

chart.dateFormatter.dateFormat = "yyyy-MM-dd";
chart.dateFormatter.inputDateFormat = "yyyy-MM-dd";

var categoryAxis = chart.yAxes.push(new am4charts.CategoryAxis());
categoryAxis.dataFields.category = "category";
categoryAxis.renderer.grid.template.disabled = true;
categoryAxis.renderer.labels.template.paddingRight = 25;
categoryAxis.renderer.minGridDistance = 10;
categoryAxis.renderer.innerRadius = -60;
categoryAxis.renderer.radius = 60;

var dateAxis = chart.xAxes.push(new am4charts.DateAxis());
dateAxis.renderer.minGridDistance = 70;
dateAxis.baseInterval = { count: 1, timeUnit: "day" };

dateAxis.renderer.tooltipLocation = 0;
dateAxis.startLocation = -0.5;
dateAxis.renderer.line.strokeDasharray = "1,4";
dateAxis.renderer.line.strokeOpacity = 0.7;
dateAxis.tooltip.background.fillOpacity = 0.2;
dateAxis.tooltip.background.cornerRadius = 5;
dateAxis.tooltip.label.fill = new am4core.InterfaceColorSet().getFor("alternativeBackground");
dateAxis.tooltip.label.paddingTop = 7;

var labelTemplate = dateAxis.renderer.labels.template;
labelTemplate.verticalCenter = "middle";
labelTemplate.fillOpacity = 0.7;
labelTemplate.background.fill =  new am4core.InterfaceColorSet().getFor("background");
labelTemplate.background.fillOpacity = 1;
labelTemplate.padding(7,7,7,7);

var categoryAxisLabelTemplate = categoryAxis.renderer.labels.template;
categoryAxisLabelTemplate.horizontalCenter = "left";
categoryAxisLabelTemplate.adapter.add("rotation", function (rotation, target) {
  var position = dateAxis.valueToPosition(dateAxis.min);
  return dateAxis.renderer.positionToAngle(position) + 90;
})

var series1 = chart.series.push(new am4plugins_timeline.CurveColumnSeries());
series1.columns.template.height = am4core.percent(20);
series1.columns.template.tooltipText = "{task}: [bold]{openDateX}[/] - [bold]{dateX}[/]";

series1.dataFields.openDateX = "start";
series1.dataFields.dateX = "end";
series1.dataFields.categoryY = "category";
series1.columns.template.propertyFields.fill = "color"; // get color from data
series1.columns.template.propertyFields.stroke = "color";
series1.columns.template.strokeOpacity = 0;

var bullet = new am4charts.CircleBullet();
series1.bullets.push(bullet);
bullet.circle.radius = 3;
bullet.circle.strokeOpacity = 0;
bullet.propertyFields.fill = "color";
bullet.locationX = 0;


var bullet2 = new am4charts.CircleBullet();
series1.bullets.push(bullet2);
bullet2.circle.radius = 3;
bullet2.circle.strokeOpacity = 0;
bullet2.propertyFields.fill = "color";
bullet2.locationX = 1;

chart.scrollbarX = new am4core.Scrollbar();
chart.scrollbarX.align = "center"
chart.scrollbarX.width = am4core.percent(90);

var cursor = new am4plugins_timeline.CurveCursor();
chart.cursor = cursor;
cursor.xAxis = dateAxis;
cursor.yAxis = categoryAxis;
cursor.lineY.disabled = true;
cursor.lineX.strokeDasharray = "1,4";
cursor.lineX.strokeOpacity = 1;

dateAxis.renderer.tooltipLocation2 = 0;
categoryAxis.cursorTooltipEnabled = false;

}); // end am4core.ready()
</script>

<!-- HTML -->
<div id="chartdiv"></div>