Feel free to share demo-related thoughts here.
If you have technical questions, please create a support ticket in the DevExpress Support Center.
Thank you for the feedback!
If you have technical questions, please create a support ticket in the DevExpress Support Center.
Backend API
import React from 'react';
import Gantt, {
Tasks, Dependencies, Resources, ResourceAssignments, Column, Editing,
} from 'devextreme-react/gantt';
import {
tasks, dependencies, resources, resourceAssignments,
} from './data.ts';
import TaskTemplate from './TaskTemplate.tsx';
function App() {
return (
<div id="form-demo">
<div className="widget-container">
<Gantt
taskListWidth={500}
height={700}
scaleType="days"
taskContentRender={TaskTemplate}>
<Tasks dataSource={tasks} />
<Dependencies dataSource={dependencies} />
<Resources dataSource={resources} />
<ResourceAssignments dataSource={resourceAssignments} />
<Column dataField="title" caption="Subject" width={300} />
<Column dataField="start" caption="Start Date" />
<Column dataField="end" caption="End Date" />
<Editing enabled />
</Gantt>
</div>
</div>
);
}
export default App;
import React from 'react';
import Gantt, {
Tasks,
Dependencies,
Resources,
ResourceAssignments,
Column,
Editing,
} from 'devextreme-react/gantt';
import {
tasks, dependencies, resources, resourceAssignments,
} from './data.js';
import TaskTemplate from './TaskTemplate.js';
function App() {
return (
<div id="form-demo">
<div className="widget-container">
<Gantt
taskListWidth={500}
height={700}
scaleType="days"
taskContentRender={TaskTemplate}
>
<Tasks dataSource={tasks} />
<Dependencies dataSource={dependencies} />
<Resources dataSource={resources} />
<ResourceAssignments dataSource={resourceAssignments} />
<Column
dataField="title"
caption="Subject"
width={300}
/>
<Column
dataField="start"
caption="Start Date"
/>
<Column
dataField="end"
caption="End Date"
/>
<Editing enabled />
</Gantt>
</div>
</div>
);
}
export default App;
import React from 'react';
function getImagePath(taskId: number) {
const imgPath = '../../../../images/employees';
let img = taskId < 10 ? `0${taskId}` : taskId;
img = `${imgPath}/${img}.png`;
return img;
}
function getTaskColor(taskId: number) {
const color = taskId % 6;
return `custom-task-color-${color}`;
}
export default function TaskTemplate({ taskData, taskSize, taskResources }) {
return (
<div className={`custom-task ${getTaskColor(taskData.id)}`} style={ { width: `${taskSize.width}px` } }>
<div className="custom-task-img-wrapper">
<img className="custom-task-img" src={getImagePath(taskData.id)} />
</div>
<div className='custom-task-wrapper'>
<div className='custom-task-title'>{taskData.title}</div>
<div className='custom-task-row'>{taskResources[0].text}</div>
</div>
<div className='custom-task-progress' style={ { width: `${taskData.progress}%` } }></div>
</div>
);
}
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App.tsx';
ReactDOM.render(
<App />,
document.getElementById('app'),
);
export const currentDate = new Date(Date.now());
const month = currentDate.getMonth();
const year = currentDate.getFullYear();
export const tasks = [{
id: 1,
parentId: 0,
title: 'Analysis/Software Requirements',
start: new Date(year, month, 1),
end: new Date(year, month, 28),
progress: 31,
}, {
id: 2,
parentId: 1,
title: 'Conduct needs analysis',
start: new Date(year, month, 1),
end: new Date(year, month, 3),
progress: 15,
}, {
id: 3,
parentId: 1,
title: 'Draft preliminary software specifications',
start: new Date(year, month, 3),
end: new Date(year, month, 5),
progress: 30,
}, {
id: 4,
parentId: 1,
title: 'Review software specifications/budget with team',
start: new Date(year, month, 4),
end: new Date(year, month, 6),
progress: 60,
}, {
id: 5,
parentId: 1,
title: 'Incorporate feedback on software specifications',
start: new Date(year, month, 6),
end: new Date(year, month, 8),
progress: 45,
}, {
id: 6,
parentId: 1,
title: 'Develop delivery timeline',
start: new Date(year, month, 8),
end: new Date(year, month, 14),
progress: 15,
}, {
id: 7,
parentId: 1,
title: 'Obtain approvals to proceed (concept, timeline, budget)',
start: new Date(year, month, 14),
end: new Date(year, month, 20),
progress: 15,
}, {
id: 8,
parentId: 1,
title: 'Draft preliminary software specifications',
start: new Date(year, month, 20),
end: new Date(year, month, 25),
progress: 0,
}, {
id: 9,
parentId: 1,
title: 'Secure required resources',
start: new Date(year, month, 25),
end: new Date(year, month, 28),
progress: 0,
}];
export const dependencies = [{
id: 1,
predecessorId: 2,
successorId: 3,
type: 0,
}, {
id: 2,
predecessorId: 3,
successorId: 4,
type: 0,
}, {
id: 3,
predecessorId: 4,
successorId: 5,
type: 0,
}, {
id: 4,
predecessorId: 5,
successorId: 6,
type: 0,
}, {
id: 5,
predecessorId: 6,
successorId: 7,
type: 0,
}, {
id: 6,
predecessorId: 7,
successorId: 8,
type: 0,
}, {
id: 7,
predecessorId: 8,
successorId: 9,
type: 0,
}];
export const resources = [{
id: 1,
text: 'John Heart',
}, {
id: 2,
text: 'Paul Peyton',
}, {
id: 3,
text: 'Robert Reagan',
}, {
id: 4,
text: 'Greta Sims',
}, {
id: 5,
text: 'Brett Wade',
}, {
id: 6,
text: 'Sandra Johnson',
}, {
id: 7,
text: 'Kevin Carter',
}, {
id: 8,
text: 'Cynthia Stanwick',
}, {
id: 9,
text: 'Olivia Samuelson',
}];
export const resourceAssignments = [{
id: 0,
taskId: 1,
resourceId: 1,
}, {
id: 1,
taskId: 2,
resourceId: 2,
}, {
id: 2,
taskId: 3,
resourceId: 3,
}, {
id: 3,
taskId: 4,
resourceId: 4,
}, {
id: 4,
taskId: 5,
resourceId: 5,
}, {
id: 5,
taskId: 6,
resourceId: 6,
}, {
id: 6,
taskId: 7,
resourceId: 7,
}, {
id: 7,
taskId: 8,
resourceId: 8,
}, {
id: 8,
taskId: 9,
resourceId: 9,
}];
window.exports = window.exports || {};
window.config = {
transpiler: 'ts',
typescriptOptions: {
module: 'system',
emitDecoratorMetadata: true,
experimentalDecorators: true,
jsx: 'react',
},
meta: {
'react': {
'esModule': true,
},
'typescript': {
'exports': 'ts',
},
'devextreme/time_zone_utils.js': {
'esModule': true,
},
'devextreme/localization.js': {
'esModule': true,
},
'devextreme/viz/palette.js': {
'esModule': true,
},
},
paths: {
'npm:': 'https://unpkg.com/',
},
defaultExtension: 'js',
map: {
'ts': 'npm:plugin-typescript@4.2.4/lib/plugin.js',
'typescript': 'npm:typescript@4.2.4/lib/typescript.js',
'react': 'npm:react@17.0.2/umd/react.development.js',
'react-dom': 'npm:react-dom@17.0.2/umd/react-dom.development.js',
'prop-types': 'npm:prop-types@15.8.1/prop-types.js',
'rrule': 'npm:rrule@2.6.4/dist/es5/rrule.js',
'luxon': 'npm:luxon@1.28.1/build/global/luxon.min.js',
'es6-object-assign': 'npm:es6-object-assign@1.1.0',
'devextreme': 'npm:devextreme@24.1.7/cjs',
'devextreme-react': 'npm:devextreme-react@24.1.7/cjs',
'jszip': 'npm:jszip@3.10.1/dist/jszip.min.js',
'devextreme-quill': 'npm:devextreme-quill@1.7.1/dist/dx-quill.min.js',
'devexpress-diagram': 'npm:devexpress-diagram@2.2.12/dist/dx-diagram.js',
'devexpress-gantt': 'npm:devexpress-gantt@4.1.56/dist/dx-gantt.js',
'@devextreme/runtime': 'npm:@devextreme/runtime@3.0.13',
'inferno': 'npm:inferno@7.4.11/dist/inferno.min.js',
'inferno-compat': 'npm:inferno-compat/dist/inferno-compat.min.js',
'inferno-create-element': 'npm:inferno-create-element@7.4.11/dist/inferno-create-element.min.js',
'inferno-dom': 'npm:inferno-dom/dist/inferno-dom.min.js',
'inferno-hydrate': 'npm:inferno-hydrate@7.4.11/dist/inferno-hydrate.min.js',
'inferno-clone-vnode': 'npm:inferno-clone-vnode/dist/inferno-clone-vnode.min.js',
'inferno-create-class': 'npm:inferno-create-class/dist/inferno-create-class.min.js',
'inferno-extras': 'npm:inferno-extras/dist/inferno-extras.min.js',
'devextreme-cldr-data': 'npm:devextreme-cldr-data@1.0.3',
// SystemJS plugins
'plugin-babel': 'npm:systemjs-plugin-babel@0.0.25/plugin-babel.js',
'systemjs-babel-build': 'npm:systemjs-plugin-babel@0.0.25/systemjs-babel-browser.js',
// Prettier
'prettier/standalone': 'npm:prettier@2.8.8/standalone.js',
'prettier/parser-html': 'npm:prettier@2.8.8/parser-html.js',
},
packages: {
'devextreme': {
defaultExtension: 'js',
},
'devextreme-react': {
main: 'index.js',
},
'devextreme/events/utils': {
main: 'index',
},
'devextreme/localization/messages': {
format: 'json',
defaultExtension: 'json',
},
'devextreme/events': {
main: 'index',
},
'es6-object-assign': {
main: './index.js',
defaultExtension: 'js',
},
},
packageConfigPaths: [
'npm:@devextreme/*/package.json',
'npm:@devextreme/runtime@3.0.13/inferno/package.json',
],
babelOptions: {
sourceMaps: false,
stage0: true,
react: true,
},
};
System.config(window.config);
import React from 'react';
function getImagePath(taskId) {
const imgPath = '../../../../images/employees';
let img = taskId < 10 ? `0${taskId}` : taskId;
img = `${imgPath}/${img}.png`;
return img;
}
function getTaskColor(taskId) {
const color = taskId % 6;
return `custom-task-color-${color}`;
}
export default function TaskTemplate({ taskData, taskSize, taskResources }) {
return (
<div
className={`custom-task ${getTaskColor(taskData.id)}`}
style={{ width: `${taskSize.width}px` }}
>
<div className="custom-task-img-wrapper">
<img
className="custom-task-img"
src={getImagePath(taskData.id)}
/>
</div>
<div className="custom-task-wrapper">
<div className="custom-task-title">{taskData.title}</div>
<div className="custom-task-row">{taskResources[0].text}</div>
</div>
<div
className="custom-task-progress"
style={{ width: `${taskData.progress}%` }}
></div>
</div>
);
}
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App.js';
ReactDOM.render(<App />, document.getElementById('app'));
export const currentDate = new Date(Date.now());
const month = currentDate.getMonth();
const year = currentDate.getFullYear();
export const tasks = [
{
id: 1,
parentId: 0,
title: 'Analysis/Software Requirements',
start: new Date(year, month, 1),
end: new Date(year, month, 28),
progress: 31,
},
{
id: 2,
parentId: 1,
title: 'Conduct needs analysis',
start: new Date(year, month, 1),
end: new Date(year, month, 3),
progress: 15,
},
{
id: 3,
parentId: 1,
title: 'Draft preliminary software specifications',
start: new Date(year, month, 3),
end: new Date(year, month, 5),
progress: 30,
},
{
id: 4,
parentId: 1,
title: 'Review software specifications/budget with team',
start: new Date(year, month, 4),
end: new Date(year, month, 6),
progress: 60,
},
{
id: 5,
parentId: 1,
title: 'Incorporate feedback on software specifications',
start: new Date(year, month, 6),
end: new Date(year, month, 8),
progress: 45,
},
{
id: 6,
parentId: 1,
title: 'Develop delivery timeline',
start: new Date(year, month, 8),
end: new Date(year, month, 14),
progress: 15,
},
{
id: 7,
parentId: 1,
title: 'Obtain approvals to proceed (concept, timeline, budget)',
start: new Date(year, month, 14),
end: new Date(year, month, 20),
progress: 15,
},
{
id: 8,
parentId: 1,
title: 'Draft preliminary software specifications',
start: new Date(year, month, 20),
end: new Date(year, month, 25),
progress: 0,
},
{
id: 9,
parentId: 1,
title: 'Secure required resources',
start: new Date(year, month, 25),
end: new Date(year, month, 28),
progress: 0,
},
];
export const dependencies = [
{
id: 1,
predecessorId: 2,
successorId: 3,
type: 0,
},
{
id: 2,
predecessorId: 3,
successorId: 4,
type: 0,
},
{
id: 3,
predecessorId: 4,
successorId: 5,
type: 0,
},
{
id: 4,
predecessorId: 5,
successorId: 6,
type: 0,
},
{
id: 5,
predecessorId: 6,
successorId: 7,
type: 0,
},
{
id: 6,
predecessorId: 7,
successorId: 8,
type: 0,
},
{
id: 7,
predecessorId: 8,
successorId: 9,
type: 0,
},
];
export const resources = [
{
id: 1,
text: 'John Heart',
},
{
id: 2,
text: 'Paul Peyton',
},
{
id: 3,
text: 'Robert Reagan',
},
{
id: 4,
text: 'Greta Sims',
},
{
id: 5,
text: 'Brett Wade',
},
{
id: 6,
text: 'Sandra Johnson',
},
{
id: 7,
text: 'Kevin Carter',
},
{
id: 8,
text: 'Cynthia Stanwick',
},
{
id: 9,
text: 'Olivia Samuelson',
},
];
export const resourceAssignments = [
{
id: 0,
taskId: 1,
resourceId: 1,
},
{
id: 1,
taskId: 2,
resourceId: 2,
},
{
id: 2,
taskId: 3,
resourceId: 3,
},
{
id: 3,
taskId: 4,
resourceId: 4,
},
{
id: 4,
taskId: 5,
resourceId: 5,
},
{
id: 5,
taskId: 6,
resourceId: 6,
},
{
id: 6,
taskId: 7,
resourceId: 7,
},
{
id: 7,
taskId: 8,
resourceId: 8,
},
{
id: 8,
taskId: 9,
resourceId: 9,
},
];
<!DOCTYPE html>
<html lang="en">
<head>
<title>DevExtreme Demo</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0" />
<link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/24.1.7/css/dx.light.css" />
<link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/24.1.7/css/dx-gantt.min.css" />
<link rel="stylesheet" type="text/css" href="styles.css" />
<script src="https://unpkg.com/core-js@2.6.12/client/shim.min.js"></script>
<script src="https://unpkg.com/systemjs@0.21.3/dist/system.js"></script>
<script type="text/javascript" src="config.js"></script>
<script type="text/javascript">
System.import("./index.tsx");
</script>
</head>
<body class="dx-viewport">
<div class="demo-container">
<div id="app"></div>
</div>
</body>
</html>
#gantt {
height: 700px;
}
.custom-task-color-0 {
background-color: #5c57c9;
}
.custom-task-color-1 {
background-color: #35b86b;
}
.custom-task-color-2 {
background-color: #4796ce;
}
.custom-task-color-3 {
background-color: #ce4776;
}
.custom-task-color-4 {
background-color: #ce5b47;
}
.custom-task-color-5 {
background-color: #f78119;
}
.custom-task-color-6 {
background-color: #9f47ce;
}
.custom-task {
max-height: 48px;
height: 100%;
display: block;
overflow: hidden;
}
.custom-task-wrapper {
padding: 8px;
color: #fff;
}
.custom-task-wrapper > * {
display: block;
overflow: hidden;
text-overflow: ellipsis;
}
.custom-task-img-wrapper {
float: left;
width: 32px;
height: 32px;
border-radius: 50%;
margin: 8px;
background-color: #fff;
overflow: hidden;
}
.custom-task-img {
width: 32px;
}
.custom-task-title {
font-weight: 600;
font-size: 13px;
}
.custom-task-row {
font-size: 11px;
}
.custom-task-progress {
position: absolute;
left: 0;
bottom: 0;
width: 0%;
height: 4px;
background: rgba(0, 0, 0, 0.3);
}
.dx-gantt .dx-row {
height: 63px;
}
Implementation: Use the taskContentTemplate template to customize and align task information within the template container. For each task, use the item property to obtain task information (title, resource, progress) and wrap it into div elements. Then, apply CSS styles to these div elements and place them into the container.