block by mpmckenna8 96eba3f746e859e5b4cef685178c14fb

D3.js v4 Gantt Chart, example 3

Full Screen

forked from dk8996‘s block: D3.js Gantt Chart, example 3

index.html

<!DOCTYPE html>
<html>
<head>
<title>Gantt Chart Example 3</title>
<link type="text/css" href="//mbostock.github.io/d3/style.css" rel="stylesheet" />
<link type="text/css" href="example.css" rel="stylesheet" />
</head>
<body>
	<button type="button" onclick="addTask()">Add Task</button>
	<button type="button" onclick="removeTask()">Remove Task</button>
	<button type="button" onclick="changeTimeDomain('1hr')">1 HR</button>
	<button type="button" onclick="changeTimeDomain('3hr')">3 HR</button>
	<button type="button" onclick="changeTimeDomain('6hr')">6 HR</button>
        <button type="button" onclick="changeTimeDomain('1day')">1 DAY</button>
        <button type="button" onclick="changeTimeDomain('1week')">1 WEEK</button>
</body>
</html>
  <script type="text/javascript" src="//d3js.org/d3.v4.min.js"></script>
	<script src="https://d3js.org/d3-time.v1.min.js"></script>
	<script type="text/javascript" src="//d3js.org/d3-time-format.min.js"></script>

	<script type="text/javascript" src="gantt.js"></script>
<script type="text/javascript" src="example3.js"></script>

example.css

html,body,#wrapper {
	width: 100%;
	height: 100%;
	margin: 0px;
}

.chart {
	font-family: Arial, sans-serif;
	font-size: 12px;
}

.axis path,.axis line {
	fill: none;
	stroke: #000;
	shape-rendering: crispEdges;
}

.bar {
	fill: #33b5e5;
}

.bar-failed {
	fill: #CC0000;
}

.bar-running {
	fill: #669900;
}

.bar-succeeded {
	fill: #33b5e5;
}

.bar-killed {
	fill: #ffbb33;
}

#forkme_banner {
	display: block;
	position: absolute;
	top: 0;
	right: 5px;
	z-index: 10;
	padding: 10px 40px 10px 5px;
	color: #fff;
	background:
		url('http://dk8996.github.io/Gantt-Chart/images/blacktocat.png')
		#0090ff no-repeat 95% 50%;
	font-weight: 700;
	box-shadow: 0 0 10px rgba(0, 0, 0, .5);
	border-bottom-left-radius: 2px;
	border-bottom-right-radius: 2px;
	text-decoration: none;
}

#twittme_banner {
	display: block;
	position: absolute;
	top: 0;
	right: 180px;
	z-index: 10;
	padding: 10px 40px 10px 5px;
	color: #fff;
	background:
		url('http://dk8996.github.io/Gantt-Chart/images/twitter.png')
		#0090ff no-repeat 95% 50%;
	font-weight: 700;
	box-shadow: 0 0 10px rgba(0, 0, 0, .5);
	border-bottom-left-radius: 2px;
	border-bottom-right-radius: 2px;
	text-decoration: none;
}

example3.js

var tasks = [
{"startDate":new Date("Sun Dec 09 00:00:45 EST 2012"),"endDate":new Date("Sun Dec 09 02:36:45 EST 2012"),"taskName":"E Job","status":"RUNNING"},
{"startDate":new Date("Sun Dec 09 08:49:53 EST 2012"),"endDate":new Date("Sun Dec 09 06:34:04 EST 2012"),"taskName":"D Job","status":"RUNNING"},
{"startDate":new Date("Sun Dec 09 03:27:35 EST 2012"),"endDate":new Date("Sun Dec 09 03:58:43 EST 2012"),"taskName":"P Job","status":"SUCCEEDED"},
{"startDate":new Date("Sun Dec 09 03:27:35 EST 2012"),"endDate":new Date("Sun Dec 09 03:58:43 EST 2012"),"taskName":"N Job","status":"KILLED"}
];

// var svg2 = d3.select("body").append("svg")
// .attr("width", 960)
// .attr("height", 100)

// svg2.append("text")
//   .text(d3.timeDay.offset(getEndDate(), -7))
//   .attr("y", 50)

var taskStatus = {
    "SUCCEEDED" : "bar",
    "FAILED" : "bar-failed",
    "RUNNING" : "bar-running",
    "KILLED" : "bar-killed"
};

var taskNames = [ "D Job", "P Job", "E Job", "A Job", "N Job" ];

tasks.sort(function(a, b) {
    return a.endDate - b.endDate;
});
var maxDate = tasks[tasks.length - 1].endDate;
tasks.sort(function(a, b) {
    return a.startDate - b.startDate;
});
var minDate = tasks[0].startDate;

var format = "%H:%M";
var timeDomainString = "1day";

var gantt = d3.gantt().height(450).width(800).taskTypes(taskNames).taskStatus(taskStatus).tickFormat(format);

// gantt.timeDomainMode("fixed");
changeTimeDomain(timeDomainString);
gantt(tasks);

function changeTimeDomain(timeDomainString) {
    this.timeDomainString = timeDomainString;
    switch (timeDomainString) {
    case "1hr":
      format = "%H:%M:%S";
      gantt.timeDomain([ d3.timeHour.offset(getEndDate(), -1), getEndDate() ]);
      break;
    case "3hr":
      format = "%H:%M";
      gantt.timeDomain([ d3.timeHour.offset(getEndDate(), -3), getEndDate() ]);
      break;

    case "6hr":
      format = "%H:%M";
      gantt.timeDomain([ d3.timeHour.offset(getEndDate(), -6), getEndDate() ]);
      break;

    case "1day":
			format = "%H:%M";
			gantt.timeDomain([ d3.timeDay.offset(getEndDate(), -1), getEndDate() ]);
			break;

    case "1week":
      format = "%a %H:%M";
      gantt.timeDomain([ d3.timeDay.offset(getEndDate(), -7), getEndDate() ]);
      break;
    default:
	format = "%H:%M"

    }
    gantt.tickFormat(format);
    gantt.redraw(tasks);
}

function getEndDate() {
    var lastEndDate = Date.now();
    if (tasks.length > 0) {
			lastEndDate = tasks[tasks.length - 1].endDate;
    }
    return lastEndDate;
}

function addTask() {

    var lastEndDate = getEndDate();
    var taskStatusKeys = Object.keys(taskStatus);
    var taskStatusName = taskStatusKeys[Math.floor(Math.random() * taskStatusKeys.length)];
    var taskName = taskNames[Math.floor(Math.random() * taskNames.length)];

    tasks.push({
	"startDate" : d3.timeHour.offset(lastEndDate, Math.ceil(1 * Math.random())),
	"endDate" : d3.timeHour.offset(lastEndDate, (Math.ceil(Math.random() * 3)) + 1),
	"taskName" : taskName,
	"status" : taskStatusName
    });

    changeTimeDomain(timeDomainString);
    gantt.redraw(tasks);
};

function removeTask() {
    tasks.pop();
    changeTimeDomain(timeDomainString);
    gantt.redraw(tasks);
};

gantt.js

/**
 * @author Dimitry Kudrayvtsev
 * @version 2.0
 *
 * Ported to d3 v4 by Keyvan Fatehi on October 16th, 2016
 */

d3.gantt = function() {
  var FIT_TIME_DOMAIN_MODE = "fit";
  var FIXED_TIME_DOMAIN_MODE = "fixed";

  var margin = {
    top : 20,
    right : 40,
    bottom : 20,
    left : 150
  };
  var timeDomainStart = d3.timeDay.offset(new Date(),-3);
  var timeDomainEnd = d3.timeHour.offset(new Date(),+3);
  var timeDomainMode = FIXED_TIME_DOMAIN_MODE;// fixed or fit
  var taskTypes = [];
  var taskStatus = [];
  var height = document.body.clientHeight - margin.top - margin.bottom-5;
  var width = document.body.clientWidth - margin.right - margin.left-5;

  var tickFormat = "%H:%M";

  var keyFunction = function(d) {
    return d.startDate + d.taskName + d.endDate;
  };

  var rectTransform = function(d) {
    return "translate(" + x(d.startDate) + "," + y(d.taskName) + ")";
  };

  var x,y,xAxis,yAxis;

  initAxis();

  var initTimeDomain = function() {
    if (timeDomainMode === FIT_TIME_DOMAIN_MODE) {
      if (tasks === undefined || tasks.length < 1) {
        timeDomainStart = d3.timeDay.offset(new Date(), -3);
        timeDomainEnd = d3.timeHour.offset(new Date(), +3);
        return;
      }
      tasks.sort(function(a, b) {
        return a.endDate - b.endDate;
      });
      timeDomainEnd = tasks[tasks.length - 1].endDate;
      tasks.sort(function(a, b) {
        return a.startDate - b.startDate;
      });
      timeDomainStart = tasks[0].startDate;
    }
  };

 function initAxis() {
    x = d3.scaleTime().domain([ timeDomainStart, timeDomainEnd ]).range([ 0, width ]).clamp(true);

    y = d3.scaleBand().domain(taskTypes).range([ 0, height - margin.top - margin.bottom ]).padding(0.1);

    xAxis = d3.axisBottom().scale(x).tickFormat(d3.timeFormat(tickFormat))
      .tickSize(8).tickPadding(8);

    yAxis = d3.axisLeft().scale(y).tickSize(0);
  };

  function gantt(tasks) {

    initTimeDomain();
    initAxis();

    var svg = d3.select("body")
      .append("svg")
      .attr("class", "chart")
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
      .append("g")
      .attr("class", "gantt-chart")
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
      .attr("transform", "translate(" + margin.left + ", " + margin.top + ")");
    
    svg.selectAll(".chart")
      .data(tasks, keyFunction).enter()
      .append("rect")
      .attr("rx", 5)
      .attr("ry", 5)
      .attr("class", function(d){ 
        if(taskStatus[d.status] == null){ return "bar";}
        return taskStatus[d.status];
      }) 
      .attr("y", 0)
      .attr("transform", rectTransform)
      .attr("height", function(d) { return 70; })
      .attr("width", function(d) { 
        return (x(d.endDate) - x(d.startDate)); 
      });

      svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0, " + (height - margin.top - margin.bottom) + ")")
        .transition()
        .call(xAxis);

      svg.append("g").attr("class", "y axis").transition().call(yAxis);

      return gantt;

  };

  gantt.redraw = function(tasks) {

    initTimeDomain();
    initAxis();

    var svg = d3.select("svg");
    var ganttChartGroup = svg.select(".gantt-chart");
    var rect = ganttChartGroup.selectAll("rect").data(tasks, keyFunction);

    rect.enter()
      .insert("rect",":first-child")
      .attr("rx", 5)
      .attr("ry", 5)
      .attr("class", function(d){ 
        if(taskStatus[d.status] == null){ return "bar";}
        return taskStatus[d.status];
      }) 
      .transition()
      .attr("y", 0)
      .attr("transform", rectTransform)
      .attr("height", function(d) { return y.bandwidth(); })
      .attr("width", function(d) { 
         return (x(d.endDate) - x(d.startDate)); 
      });

      rect.merge(rect).transition()
      	.attr("transform", rectTransform)
	      .attr("height", function(d) { return y.bandwidth(); })
        .attr("width", function(d) { 
           return (x(d.endDate) - x(d.startDate));
        });

        rect.exit().remove();

        svg.select(".x").transition().call(xAxis);
        svg.select(".y").transition().call(yAxis);

        return gantt;
  };

  gantt.margin = function(value) {
    if (!arguments.length)
      return margin;
    margin = value;
    return gantt;
  };

  gantt.timeDomain = function(value) {
    if (!arguments.length)
      return [ timeDomainStart, timeDomainEnd ];
    timeDomainStart = +value[0], timeDomainEnd = +value[1];
    return gantt;
  };

    /**
  * @param {string}
  *                vale The value can be "fit" - the domain fits the data or
  *                "fixed" - fixed domain.
  */
  gantt.timeDomainMode = function(value) {
    if (!arguments.length)
      return timeDomainMode;
    timeDomainMode = value;
    return gantt;

  };

  gantt.taskTypes = function(value) {
    if (!arguments.length)
      return taskTypes;
    taskTypes = value;
    return gantt;
  };

  gantt.taskStatus = function(value) {
    if (!arguments.length)
      return taskStatus;
    taskStatus = value;
    return gantt;
  };

  gantt.width = function(value) {
    if (!arguments.length)
      return width;
    width = +value;
    return gantt;
  };

  gantt.height = function(value) {
    if (!arguments.length)
      return height;
    height = +value;
    return gantt;
  };

  gantt.tickFormat = function(value) {
    if (!arguments.length)
      return tickFormat;
    tickFormat = value;
    return gantt;
  };

  return gantt;
};