react-gantt-elastic
Version:
Gantt chart. Elastic javascript gantt chart. React gantt. Project manager responsive gantt. jquery gantt.
514 lines (494 loc) • 16.2 kB
HTML
<html charset="utf-8">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
<title>GanttElastic editor demo</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.4/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/dayjs"></script>
<!--
<script src="https://unpkg.com/gantt-elastic@0.9.5/dist/GanttElastic.umd.js"></script>
-->
<!--
<script src="https://cdn.jsdelivr.net/npm/gantt-elastic/dist/GanttElastic.umd.js"></script>
-->
<script src="https://unpkg.com/gantt-elastic-header@0.1.11/dist/Header.umd.js"></script>
<script src="../dist/GanttElastic.umd.js"></script>
</head>
<body style="font-family:Roboto, Arial, sans-serif;">
<div style="width:100%;height:100%">
<div id="app" v-if="!destroy">
<gantt-elastic :tasks="tasks" :options="options" :dynamic-style="dynamicStyle">
<gantt-header slot="header" :options="headerOptions"></gantt-header>
<gantt-footer slot="footer"></gantt-footer>
</gantt-elastic>
</div>
</div>
modify task<br />
<input type="range" min="1" max="24" id="time-zoom" /><br />
<input type="number" value="0" id="row" placeholder="which row?" />
<input type="text" id="name" placeholder="name" value="label" />
<input type="text" id="value" value="test" placeholder="value" onkeyup="update()" />
<br />
<input type="number" value="0" id="delrow" placeholder="which row?" />
<button onclick="deleteRow()">Delete</button>
<br />
<input type="number" id="progRow" value="0" /><input
type="range"
min="0"
max="100"
oninput="progressChange()"
id="progress"
/>
<br />
<button onclick="addTask()">Add task</button>
<button onclick="addTasks()">Add tasks</button><br />
<button onclick="destroy()">Destroy</button><br />
<button onclick="changeOptions()">Change options</button>
<script>
// just helper to get current dates
function getDate(hours) {
const currentDate = new Date();
const currentYear = currentDate.getFullYear();
const currentMonth = currentDate.getMonth() + 1;
const currentDay = currentDate.getDate();
const timeStamp = new Date(`${currentYear}-${currentMonth}-${currentDay} 00:00:00`).getTime();
return new Date(timeStamp + hours * 60 * 60 * 1000).getTime();
}
let tasks = [
{
id: 1,
label: 'Make some noise',
user:
'<a href="https://www.google.com/search?q=John+Doe" target="_blank" style="color:#0077c0;">John Doe</a>',
start: getDate(-24 * 5),
duration: 15 * 24 * 60 * 60 * 1000,
percent: 85,
type: 'project'
//collapsed: true,
},
{
id: 2,
label: 'With great power comes great responsibility',
user:
'<a href="https://www.google.com/search?q=Peter+Parker" target="_blank" style="color:#0077c0;">Peter Parker</a>',
parentId: 1,
start: getDate(-24 * 4),
duration: 4 * 24 * 60 * 60 * 1000,
percent: 50,
type: 'milestone',
collapsed: true,
style: {
base: {
fill: '#1EBC61',
stroke: '#0EAC51'
}
/*'tree-row-bar': {
fill: '#1EBC61',
stroke: '#0EAC51'
},
'tree-row-bar-polygon': {
stroke: '#0EAC51'
}*/
}
},
{
id: 3,
label: 'Courage is being scared to death, but saddling up anyway.',
user:
'<a href="https://www.google.com/search?q=John+Wayne" target="_blank" style="color:#0077c0;">John Wayne</a>',
parentId: 2,
start: getDate(-24 * 3),
duration: 2 * 24 * 60 * 60 * 1000,
percent: 100,
type: 'task'
},
{
id: 4,
label: 'Put that toy AWAY!',
user:
'<a href="https://www.google.com/search?q=Clark+Kent" target="_blank" style="color:#0077c0;">Clark Kent</a>',
start: getDate(-24 * 2),
duration: 2 * 24 * 60 * 60 * 1000,
percent: 50,
type: 'task',
dependentOn: [3]
},
{
id: 5,
label: 'One billion, gajillion, fafillion... shabadylu...mil...shabady......uh, Yen.',
user:
'<a href="https://www.google.com/search?q=Austin+Powers" target="_blank" style="color:#0077c0;">Austin Powers</a>',
parentId: 4,
start: getDate(0),
duration: 2 * 24 * 60 * 60 * 1000,
percent: 10,
type: 'milestone',
style: {
base: {
fill: '#0287D0',
stroke: '#0077C0'
}
}
},
{
id: 6,
label: 'Butch Mario and the Luigi Kid',
user:
'<a href="https://www.google.com/search?q=Mario+Bros" target="_blank" style="color:#0077c0;">Mario Bros</a>',
parentId: 5,
start: getDate(24),
duration: 1 * 24 * 60 * 60 * 1000,
percent: 50,
type: 'task',
collapsed: true,
style: {
base: {
fill: '#8E44AD',
stroke: '#7E349D'
}
}
},
{
id: 7,
label: 'Devon, the old man wanted me, it was his dying request',
user:
'<a href="https://www.google.com/search?q=Knight+Rider" target="_blank" style="color:#0077c0;">Knight Rider</a>',
parentId: 2,
dependentOn: [6],
start: getDate(24 * 2),
duration: 4 * 60 * 60 * 1000,
percent: 20,
type: 'task',
collapsed: true
},
{
id: 8,
label: 'Hey, Baby! Anybody ever tell you I have beautiful eyes?',
user:
'<a href="https://www.google.com/search?q=Johhny+Bravo" target="_blank" style="color:#0077c0;">Johhny Bravo</a>',
parentId: 7,
dependentOn: [7],
start: dayjs()
.startOf('day')
.valueOf(),
end: dayjs()
.startOf('day')
.add(1, 'day')
.valueOf(),
percent: 0,
type: 'task'
},
{
id: 9,
label: 'This better be important, woman. You are interrupting my very delicate calculations.',
user:
'<a href="https://www.google.com/search?q=Dexter\'s+Laboratory" target="_blank" style="color:#0077c0;">Dexter\'s Laboratory</a>',
parentId: 8,
dependentOn: [8, 7],
start: getDate(24 * 4),
duration: 4 * 60 * 60 * 1000,
percent: 20,
type: 'task',
style: {
base: {
fill: '#8E44AD',
stroke: '#7E349D'
}
/*'tree-row-bar-polygon': {
stroke: '#7E349D'
},
'tree-row-bar': {
fill: '#8E44AD',
stroke: '#7E349D'
}*/
}
},
{
id: 10,
label: 'current task',
user:
'<a href="https://www.google.com/search?q=Johnattan+Owens" target="_blank" style="color:#0077c0;">Johnattan Owens</a>',
start: getDate(24 * 5),
duration: 24 * 60 * 60 * 1000,
percent: 0,
type: 'task'
},
{
id: 11,
label: 'test task',
user:
'<a href="https://www.google.com/search?q=Johnattan+Owens" target="_blank" style="color:#0077c0;">Johnattan Owens</a>',
start: getDate(24 * 6),
duration: 24 * 60 * 60 * 1000,
percent: 0,
type: 'task'
},
{
id: 12,
label: 'test task',
user:
'<a href="https://www.google.com/search?q=Johnattan+Owens" target="_blank" style="color:#0077c0;">Johnattan Owens</a>',
start: getDate(24 * 7),
duration: 24 * 60 * 60 * 1000,
percent: 0,
type: 'task',
parentId: 11
},
{
id: 13,
label: 'test task',
user:
'<a href="https://www.google.com/search?q=Johnattan+Owens" target="_blank" style="color:#0077c0;">Johnattan Owens</a>',
start: getDate(24 * 8),
duration: 24 * 60 * 60 * 1000,
percent: 0,
type: 'task'
},
{
id: 14,
label: 'test task',
user:
'<a href="https://www.google.com/search?q=Johnattan+Owens" target="_blank" style="color:#0077c0;">Johnattan Owens</a>',
start: getDate(24 * 9),
end: getDate(24 * 12),
percent: 0,
type: 'task'
},
{
id: 15,
label: 'test task',
user:
'<a href="https://www.google.com/search?q=Johnattan+Owens" target="_blank" style="color:#0077c0;">Johnattan Owens</a>',
start: getDate(24 * 16),
duration: 24 * 60 * 60 * 1000,
percent: 0,
type: 'task'
}
];
let options = {
taskMapping: {
progress: 'percent'
},
maxRows: 100,
maxHeight: 300,
title: {
label: 'Your project title as html (link or whatever...)',
html: false
},
row: {
height: 24
},
calendar: {
hour: {
display: true
}
},
chart: {
progress: {
bar: false
},
expander: {
display: true
}
},
taskList: {
expander: {
straight: false
},
columns: [
{
id: 1,
label: 'ID',
value: 'id',
width: 40
},
{
id: 2,
label: 'Description',
value: 'label',
width: 200,
expander: true,
html: true,
events: {
click({ data, column }) {
alert('description clicked!\n' + data.label);
}
}
},
{
id: 3,
label: 'Assigned to',
value: 'user',
width: 130,
html: true
},
{
id: 3,
label: 'Start',
value: task => dayjs(task.start).format('YYYY-MM-DD'),
width: 78
},
{
id: 4,
label: 'Type',
value: 'type',
width: 68
},
{
id: 5,
label: '%',
value: 'progress',
width: 35,
style: {
'task-list-header-label': {
'text-align': 'center',
width: '100%'
},
'task-list-item-value-container': {
'text-align': 'center',
width: '100%'
}
}
}
]
}
};
const headerOptions = {
title: {
label: 'Gantt elastic',
html: false
},
locale: {
Now: 'Now',
'X-Scale': 'Zoom-X',
'Y-Scale': 'Zoom-Y',
'Task list width': 'Task list',
'Before/After': 'Expand',
'Display task list': 'Task list'
}
};
// create instance
const app = (window.app = new Vue({
components: {
'gantt-header': Header,
'gantt-elastic': GanttElastic,
'gantt-footer': {
template: `<span>this is a footer</span>`
}
},
data: {
tasks: tasks.map(task => Object.assign({}, task)),
options,
dynamicStyle: {},
headerOptions,
destroy: false
}
}));
// gantt state which will be updated in realtime
let ganttState, ganttInstance;
// listen to 'gantt-elastic.ready' or 'gantt-elastic.mounted' event
// to get the gantt state for real time modification
app.$on('gantt-elastic-ready', ganttElasticInstance => {
ganttInstance = ganttElasticInstance;
ganttInstance.$on('tasks-changed', tasks => {
//console.log('tasks updated', tasks);
app.tasks = tasks;
});
ganttInstance.$on('options-changed', options => {
//console.log('options updated', options);
app.options = options;
});
ganttInstance.$on('dynamic-style-changed', style => {
console.log('style updated', style);
app.dynamicStyle = style;
});
ganttInstance.$on('chart-task-mouseenter', ({ data, event }) => {
console.log('task mouse enter', { data, event });
});
ganttInstance.$on('updated', () => {
//console.log('gantt view was updated');
});
ganttInstance.$on('destroyed', () => {
//console.log('gantt was destroyed');
});
ganttInstance.$on('times-timeZoom-updated', () => {
console.log('time zoom changed');
});
ganttInstance.$on('taskList-task-click', ({ event, data, column }) => {
console.log('task list clicked! (task)', { data, column });
});
});
// mount gantt to DOM
app.$mount('#app');
document.getElementById('time-zoom').addEventListener('input', function timeZoomChange(ev) {
const zoom = ev.target.value;
app.options.times.timeZoom = zoom;
});
function update() {
const row = document.getElementById('row').value;
const name = document.getElementById('name').value;
const value = document.getElementById('value').value;
app.tasks[row][name] = value;
}
function deleteRow() {
const row = Number(document.getElementById('delrow').value);
app.tasks = app.tasks.filter((task, index) => {
if (index === row) {
console.log('removing task', task, index);
}
return index !== row;
});
}
function progressChange() {
const row = Number(document.getElementById('progRow').value);
const percent = Number(document.getElementById('progress').value);
app.tasks[row].progress = percent;
}
function addTask() {
const task = {
id: 88,
label:
'<a href="https://images.pexels.com/photos/423364/pexels-photo-423364.jpeg?auto=compress&cs=tinysrgb&h=650&w=940" target="_blank" style="color:#0077c0;">Yeaahh! you have added a task bro!</a>',
user:
'<a href="https://images.pexels.com/photos/423364/pexels-photo-423364.jpeg?auto=compress&cs=tinysrgb&h=650&w=940" target="_blank" style="color:#0077c0;">Awesome!</a>',
parentId: 7,
dependentOn: [7],
start: getDate(24 * 3),
duration: 1 * 24 * 60 * 60 * 1000,
percent: 50,
type: 'project'
};
app.tasks.push(task);
}
function addTasks() {
const newTasks = tasks.map(task => Object.assign({}, task));
app.tasks = newTasks;
}
function changeOptions() {
const column = app.options.taskList.columns[0];
column.label = 'Whooaa!';
column.width = 100;
column.style = {
'task-list-header-column': {
background: 'red',
color: 'white'
}
};
app.options.calendar.month = {
format: {
long: function() {
return ':P';
}
}
};
app.options.times = { timeZoom: 2 };
app.options.locale['Now'] = 'Center';
ganttInstance.fixScrollPos();
}
function destroy() {
app.destroy = true;
}
</script>
</body>
</html>