jetsum_dhtmlx_gantt
Version:
An open source JavaScript Gantt chart that helps you illustrate a project schedule in a nice-looking chart.
871 lines (812 loc) • 19.1 kB
HTML
<!DOCTYPE html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>Assign resource values to specific days</title>
<script src="../../codebase/dhtmlxgantt.js?v=7.1.9"></script>
<link rel="stylesheet" href="../../codebase/dhtmlxgantt.css?v=7.1.9">
<script src="../common/resource_project_assignments.js?v=7.1.9"></script>
<style>
html, body {
padding: 0px;
margin: 0px;
height: 100%;
}
#gantt_here {
width:100%;
height:100%;
}
.gantt_grid_scale .gantt_grid_head_cell,
.gantt_task .gantt_task_scale .gantt_scale_cell {
font-weight: bold;
font-size: 14px;
color: rgba(0, 0, 0, 0.7);
}
.resource_marker{
text-align: center;
}
.resource_marker div{
color: black;
background: none;
}
.resource_marker.resource_cell div{
font-weight: bold;
background-color: #d6d6d6;
}
.resource_marker.task_cell div {
cursor: pointer;
}
.resource_marker.workday_ok div {
}
.resource_marker.workday_over div{
color: red;
}
.owner-label{
width: 20px;
height: 20px;
line-height: 20px;
font-size: 12px;
display: inline-block;
border: 1px solid #cccccc;
border-radius: 25px;
background: #e6e6e6;
color: #6f6f6f;
margin: 0 3px;
font-weight: bold;
}
</style>
</head>
<body>
<div id="gantt_here"></div>
<script>
gantt.message({
text:[
"Click any cell of the <b>Interior office</b> item down in the resource panel in order to set resource values for specific days"
].join("<br><br>"),
expire: -1
});
gantt.config.resource_render_empty_cells = true;
gantt.config.columns = [
{name: "text", tree: true, width: 200, resize: true},
{name: "start_date", align: "center", width: 80, resize: true},
{name: "owner", align: "center", width: 75, label: "Owner", template: function (task) {
if (task.type == gantt.config.types.project) {
return "";
}
var store = gantt.getDatastore("resource");
var assignments = gantt.getTaskAssignments(task.id);
var uniqueResources = {};
var resourceCount = 0;
assignments.forEach(function(a){
if(!uniqueResources[a.resource_id]){
uniqueResources[a.resource_id] = a.resource_id;
resourceCount++;
}
});
if(!resourceCount){
return "Unassigned";
}else if(resourceCount === 1){
return store.getItem(assignments[0].resource_id).text;
}else{
var result = "";
for(var i in uniqueResources){
var owner = store.getItem(uniqueResources[i]);
if (!owner)
continue;
result += "<div class='owner-label' title='" + owner.text + "'>" + owner.text.substr(0, 1) + "</div>";
}
return result;
}
return result;
}, resize: true
},
{name: "duration", width: 60, align: "center"},
{name: "add", width: 44}
];
function getResourceAssignments(resourceId) {
var assignments;
var store = gantt.getDatastore(gantt.config.resource_store);
var resource = store.getItem(resourceId);
if(resource.$role === "task"){
assignments = gantt.getResourceAssignments(resource.$resource_id, resource.$task_id);
}else{
assignments = gantt.getResourceAssignments(resourceId);
if(store.eachItem){
store.eachItem(function(childResource){
if(childResource.$role !== "task"){
assignments = assignments.concat(gantt.getResourceAssignments(childResource.id));
}
}, resourceId);
}
}
return assignments;
}
var resourceConfig = {
columns: [
{
name: "name", label: "Name", tree:true, template: function (resource) {
return resource.text;
}
},
{
name: "workload", label: "Workload", template: function (resource) {
var totalDuration = 0;
if (resource.$role === "task"){
gantt.getResourceAssignments(resource.$resource_id, resource.$task_id).forEach(function(a){
totalDuration += a.value * a.duration;
});
}else{
getResourceAssignments(resource.id).forEach(function (assignment) {
totalDuration += Number(assignment.value) * assignment.duration;
});
}
return (totalDuration || 0) + "h";
}
}
]
};
gantt.templates.resource_cell_class = function(start_date, end_date, resource, tasks, assignments){
var css = [];
css.push("resource_marker");
if(resource.$role === "task"){
css.push("task_cell");
}else{
css.push("resource_cell");
}
var sum = assignments.reduce(function(total, assignment){
return total + Number(assignment.value);
}, 0);
if (sum <= 8) {
css.push("workday_ok");
} else {
css.push("workday_over");
}
return css.join(" ");
};
gantt.templates.resource_cell_value = function(start_date, end_date, resource, tasks, assignments){
if(resource.$role === "task"){
if(start_date < resource.end_date && end_date > resource.start_date){
for(var i = 0; i < assignments.length; i++){
var a = assignments[i];
return "<div contenteditable data-assignment-cell data-assignment-id='"+a.id+"'"+
" data-row-id='"+resource.id+"'"+
" data-task='"+resource.$task_id+"'"+
" data-start-date='"+gantt.templates.format_date(start_date)+"'"+
" data-end-date='"+gantt.templates.format_date(end_date)+"'>" + a.value + "</div>"
}
return "<div contenteditable data-assignment-cell data-empty "+
" data-row-id='"+resource.id+"'"+
" data-resource-id='"+resource.$resource_id+"'"+
" data-task='"+resource.$task_id+"'"+
" data-start-date='"+gantt.templates.format_date(start_date)+"'"+
"' data-end-date='"+gantt.templates.format_date(end_date)+"'>-</div>";
}
}else{
var sum = assignments.reduce(function(total, assignment){
return total + Number(assignment.value);
}, 0);
if(sum % 1){
sum = Math.round(sum * 10)/10;
}
if(sum){
return "<div>" + sum + "</div>";
}
return "";
}
};
gantt.attachEvent("onGanttReady", function(){
gantt.event(gantt.$container, "keypress", function(e){
var target = e.target.closest(".resourceTimeline_cell [data-assignment-cell]");
if(target){
if (e.keyCode === 13 || e.keyCode === 27) {
target.blur();
}
}
});
gantt.event(gantt.$container, "focusout", function(e){
var target = e.target.closest(".resourceTimeline_cell [data-assignment-cell]");
if(target){
var strValue = (target.innerText || "").trim();
if(strValue == "-"){
strValue = "0";
}
var value = Number(strValue);
var rowId = target.getAttribute("data-row-id");
var assignmentId = target.getAttribute("data-assignment-id");
var taskId = target.getAttribute("data-task");
var resourceId = target.getAttribute("data-resource-id");
var startDate = gantt.templates.parse_date(target.getAttribute("data-start-date"));
var endDate = gantt.templates.parse_date(target.getAttribute("data-end-date"));
var assignmentStore = gantt.getDatastore(gantt.config.resource_assignment_store);
if(isNaN(value)){
gantt.getDatastore(gantt.config.resource_store).refresh(rowId);
}else{
var task = gantt.getTask(taskId);
if(assignmentId){
var assignment = assignmentStore.getItem(assignmentId);
if(value === assignment.value){
return;
}
if(assignment.start_date.valueOf() === startDate.valueOf() && assignment.end_date.valueOf() === endDate.valueOf()){
assignment.value = value;
if(!value){
assignmentStore.removeItem(assignment.id);
}else{
assignmentStore.updateItem(assignment.id);
}
} else {
var prevChunk = null;
if(assignment.end_date.valueOf() > endDate.valueOf()){
var nextChunk = gantt.copy(assignment);
nextChunk.id = gantt.uid();
nextChunk.start_date = endDate;
nextChunk.duration = gantt.calculateDuration({
start_date: nextChunk.start_date,
end_date: nextChunk.end_date,
task: task
});
nextChunk.delay = gantt.calculateDuration({
start_date: task.start_date,
end_date: nextChunk.start_date,
task: task
});
nextChunk.mode = assignment.mode || "default";
if(nextChunk.duration !== 0){
assignmentStore.addItem(nextChunk);
}
}
if(assignment.start_date.valueOf() < startDate.valueOf()){
assignment.end_date = startDate;
assignment.duration = gantt.calculateDuration({
start_date: assignment.start_date,
end_date: assignment.end_date,
task: task
});
assignment.mode = "fixedDuration";
if(assignment.duration === 0){
assignmentStore.removeItem(assignment.id);
}else{
assignmentStore.updateItem(assignment.id);
}
}else{
assignmentStore.removeItem(assignment.id);
}
if(value){
assignmentStore.addItem({
task_id: assignment.task_id,
resource_id: assignment.resource_id,
value: value,
start_date: startDate,
end_date: endDate,
duration: gantt.calculateDuration({
start_date: startDate,
end_date: endDate,
task: task
}),
delay: gantt.calculateDuration({
start_date: task.start_date,
end_date: startDate,
task: task
}),
mode: "fixedDuration"
});
}
}
gantt.updateTaskAssignments(task.id);
gantt.updateTask(task.id);
}else if(value){
var assignment = {
task_id: taskId,
resource_id: resourceId,
value: value,
start_date: startDate,
end_date: endDate,
duration: gantt.calculateDuration({
start_date: startDate,
end_date: endDate,
task: task
}),
delay: gantt.calculateDuration({
start_date: task.start_date,
end_date: startDate,
task: task
}),
mode: "fixedDuration"
};
assignmentStore.addItem(assignment);
gantt.updateTaskAssignments(task.id);
gantt.updateTask(task.id);
}
}
}
});
})
gantt.locale.labels.section_resources = "Owners";
gantt.config.lightbox.sections = [
{ name: "description", height: 38, map_to: "text", type: "textarea", focus: true },
{ name: "resources", type: "resources", map_to: "owner", options: gantt.serverList("people"), default_value: 8},
{ name: "time", type: "duration", map_to: "auto" }
];
gantt.config.resource_store = "resource";
gantt.config.resource_property = "owner";
gantt.config.order_branch = true;
gantt.config.open_tree_initially = true;
gantt.config.layout = {
css: "gantt_container",
rows: [
{
cols: [
{view: "grid", group:"grids", scrollY: "scrollVer"},
{resizer: true, width: 1},
{view: "timeline", scrollX: "scrollHor", scrollY: "scrollVer"},
{view: "scrollbar", id: "scrollVer", group:"vertical"}
],
gravity:2
},
{resizer: true, width: 1},
{
config: resourceConfig,
cols: [
{view: "resourceGrid", group:"grids", width: 435, scrollY: "resourceVScroll" },
{resizer: true, width: 1},
{view: "resourceTimeline", scrollX: "scrollHor", scrollY: "resourceVScroll"},
{view: "scrollbar", id: "resourceVScroll", group:"vertical"}
],
gravity:1
},
{view: "scrollbar", id: "scrollHor"}
]
};
var resourcesStore = gantt.createDatastore({
name: gantt.config.resource_store,
type: "treeDatastore",
fetchTasks: true,
initItem: function (item) {
item.parent = item.parent || gantt.config.root_id;
item[gantt.config.resource_property] = item.parent;
item.open = true;
return item;
}
});
resourcesStore.attachEvent("onParse", function() {
var people = [];
resourcesStore.eachItem(function(res) {
if (res.$level === 1) {
var copy = gantt.copy(res);
copy.key = res.id;
copy.label = res.text;
copy.unit = "hours/day";
people.push(copy);
}
});
gantt.updateCollection("people", people);
});
gantt.init("gantt_here");
resourcesStore.parse([
{id: 1, text: "QA", parent:null},
{id: 2, text: "Development", parent:null},
{id: 3, text: "Sales", parent:null},
{id: 4, text: "Other", parent:null},
{id: 5, text: "Unassigned", parent:4},
{id: 6, text: "John", parent:1, unit: "hours/day" },
{id: 7, text: "Mike", parent:2, unit: "hours/day" },
{id: 8, text: "Anna", parent:2, unit: "hours/day" },
{id: 9, text: "Bill", parent:3, unit: "hours/day" },
{id: 10, text: "Floe", parent:3, unit: "hours/day" }
]);
gantt.createDataProcessor(function(entity, action, data, id){
console.log(JSON.stringify({
entity,
action,
data,
id
}, null, 2));
});
gantt.parse({
data: [
{
id: 1,
text: "Office itinerancy",
type: "project",
start_date: "02-04-2019 00:00",
duration: 17,
progress: 0.4,
parent: 0
},
{
id: 2,
text: "Office facing",
type: "project",
start_date: "02-04-2019 00:00",
duration: 8,
progress: 0.6,
parent: "1"
},
{
id: 3,
text: "Furniture installation",
type: "project",
start_date: "11-04-2019 00:00",
duration: 8,
parent: "1",
progress: 0.6,
owner: []
},
{
id: 4,
text: "The employee relocation",
type: "project",
start_date: "13-04-2019 00:00",
duration: 5,
parent: "1",
progress: 0.5,
owner: [],
priority: 3
},
{
id: 5,
text: "Interior office",
type: "task",
start_date: "03-04-2019 00:00",
duration: 7,
parent: "2",
progress: 0.6,
owner: [
{
resource_id: "6",
value: 3,
start_date: "03-04-2019 00:00",
end_date: "05-04-2019 00:00",
}],
priority: 1
},
{
id: 6,
text: "Air conditioners check",
type: "task",
start_date: "03-04-2019 00:00",
duration: 7,
parent: "2",
progress: 0.6,
owner: [
{
resource_id: "6",
value: 4,
delay: 2
}],
priority: 2
},
{
id: 7,
text: "Workplaces preparation",
type: "task",
start_date: "12-04-2019 00:00",
duration: 8,
parent: "3",
progress: 0.6,
owner: [
{
resource_id: "10",
value: 2
}]
},
{
id: 8,
text: "Preparing workplaces",
type: "task",
start_date: "14-04-2019 00:00",
duration: 5,
parent: "4",
progress: 0.5,
owner: [
{
resource_id: "10",
value: 4
},
{
resource_id: "9",
value: 5
}],
priority: 1
},
{
id: 9,
text: "Workplaces importation",
type: "task",
start_date: "21-04-2019 00:00",
duration: 4,
parent: "4",
progress: 0.5,
owner: [
{
resource_id: "7",
value: 3
}]
},
{
id: 10,
text: "Workplaces exportation",
type: "task",
start_date: "27-04-2019 00:00",
duration: 3,
parent: "4",
progress: 0.5,
owner: [
{
resource_id: "8",
value: 5
}],
priority: 2
},
{
id: 11,
text: "Product launch",
type: "project",
progress: 0.6,
start_date: "02-04-2019 00:00",
duration: 13,
owner: [
{
resource_id: "5",
value: 4
}],
parent: 0
},
{
id: 12,
text: "Perform Initial testing",
type: "task",
start_date: "03-04-2019 00:00",
duration: 5,
parent: "11",
progress: 1,
owner: [
{
resource_id: "7",
value: 6
}]
},
{
id: 13,
text: "Development",
type: "project",
start_date: "03-04-2019 00:00",
duration: 11,
parent: "11",
progress: 0.5,
owner: [
{
resource_id: "5",
value: 2
}]
},
{
id: 14,
text: "Analysis",
type: "task",
start_date: "03-04-2019 00:00",
duration: 6,
parent: "11",
owner: [
],
progress: 0.8
},
{
id: 15,
text: "Design",
type: "project",
start_date: "03-04-2019 00:00",
duration: 5,
parent: "11",
progress: 0.2,
owner: [
{
resource_id: "5",
value: 5
}]
},
{
id: 16,
text: "Documentation creation",
type: "task",
start_date: "03-04-2019 00:00",
duration: 7,
parent: "11",
progress: 0,
owner: [
{
resource_id: "7",
value: 2
}],
priority: 1
},
{
id: 17,
text: "Develop System",
type: "task",
start_date: "03-04-2019 00:00",
duration: 2,
parent: "13",
progress: 1,
owner: [
{
resource_id: "8",
value: 1
}],
priority: 2
},
{
id: 25,
text: "Beta Release",
type: "milestone",
start_date: "06-04-2019 00:00",
parent: "13",
progress: 0,
owner: [
{
resource_id: "5",
value: 1
}],
duration: 0
},
{
id: 18,
text: "Integrate System",
type: "task",
start_date: "10-04-2019 00:00",
duration: 2,
parent: "13",
progress: 0.8,
owner: [
{
resource_id: "6",
value: 2
}],
priority: 3
},
{
id: 19,
text: "Test",
type: "task",
start_date: "13-04-2019 00:00",
duration: 4,
parent: "13",
progress: 0.2,
owner: [
{
resource_id: "6",
value: 3
}]
},
{
id: 20,
text: "Marketing",
type: "task",
start_date: "13-04-2019 00:00",
duration: 4,
parent: "13",
progress: 0,
owner: [
{
resource_id: "8",
value: 4
}],
priority: 1
},
{
id: 21,
text: "Design database",
type: "task",
start_date: "03-04-2019 00:00",
duration: 4,
parent: "15",
progress: 0.5,
owner: [
{
resource_id: "6",
value: 5
}]
},
{
id: 22,
text: "Software design",
type: "task",
start_date: "03-04-2019 00:00",
duration: 4,
parent: "15",
progress: 0.1,
owner: [
{
resource_id: "8",
value: 3
}],
priority: 1
},
{
id: 23,
text: "Interface setup",
type: "task",
start_date: "03-04-2019 00:00",
duration: 5,
parent: "15",
progress: 0,
owner: [
{
resource_id: "8",
value: 5
}],
priority: 1
},
{
id: 24,
text: "Release v1.0",
type: "milestone",
start_date: "20-04-2019 00:00",
parent: "11",
progress: 0,
owner: [
{
resource_id: "5",
value: 3
}],
duration: 0
}
],
links: [
{
id: "2",
source: "2",
target: "3",
type: "0"
},
{
id: "3",
source: "3",
target: "4",
type: "0"
},
{
id: "7",
source: "8",
target: "9",
type: "0"
},
{
id: "8",
source: "9",
target: "10",
type: "0"
},
{
id: "16",
source: "17",
target: "25",
type: "0"
},
{
id: "17",
source: "18",
target: "19",
type: "0"
},
{
id: "18",
source: "19",
target: "20",
type: "0"
},
{
id: "22",
source: "13",
target: "24",
type: "0"
},
{
id: "23",
source: "25",
target: "18",
type: "0"
}
]
});
</script>
</body>