共计 21932 个字符,预计需要花费 55 分钟才能阅读完成。
摘要:本文由葡萄城技术团队于思否公布。转载请注明出处:葡萄城官网,葡萄城为开发者提供业余的开发工具、解决方案和服务,赋能开发者。
前言
甘特图是项目管理、生产排程、节点治理中十分常见的一个性能。那么,有没有一种办法可能帮忙将甘特图引入到零碎中,让数据的进度、排程数据的展现更加直观,让治理更加高效。
本葡萄明天为大家带来一个新的插件——甘特图插件。该插件是联合 SpreadJS 自身弱小电子表格能力提供的一种全新的可视化展现计划,可能无效地将生产打算、估算排期中的日程治理信息展现进去,显示要害门路上要害节点的停顿或状态。其数据来自与集算表同源的数据管理器(DataManager),通过绑定 -\> 视图的形式,将层级化的工作数据通过甘特图插件进行展现。
(通过甘特图插件展现层级化的数据)
1. 缩放和工夫刻度滚动
(通过甘特图插件实现缩放及刻度滚动)
JavaScript 代码:
var myTable; | |
var ganttSheet; | |
var adjustTierUnit = true; | |
window.onload = function() {var spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"), {sheetCount: 0}); | |
initSpread(spread); | |
initSplitView(spread); | |
}; | |
function initSpread(spread) {spread.suspendPaint(); | |
initDataSource(spread); | |
initGanttSheet(spread); | |
spread.resumePaint();} | |
function initDataSource(spread) { | |
var tableName = "Gantt_Id"; | |
var baseApiUrl = getBaseApiUrl(); | |
var apiUrl = baseApiUrl + "/" + tableName; | |
var dataManager = spread.dataManager(); | |
myTable = dataManager.addTable("myTable", { | |
batch: true, | |
remote: { | |
read: {url: apiUrl} | |
}, | |
schema: { | |
hierarchy: { | |
type: "Parent", | |
column: "parentId" | |
}, | |
columns: {id: { isPrimaryKey: true}, | |
taskNumber: {dataType: "rowOrder"} | |
} | |
} | |
}); | |
} | |
function initGanttSheet(spread) {ganttSheet = spread.addSheetTab(0, "GanttSheet", GC.Spread.Sheets.SheetType.ganttSheet); | |
var view = myTable.addView("ganttView", [{ value: "taskNumber", caption: "NO.", width: 60}, | |
{value: "name", caption: "Task Name", width: 200}, | |
{value: "duration", caption: "Duration", width: 90}, | |
{value: "predecessors", caption: "Predecessors", width: 120} | |
]); | |
view.fetch().then(function() {ganttSheet.bindGanttView(view); | |
}).then(function() {ganttSheet.project.timescale.zoomOut(); | |
}); | |
initSidePanel(ganttSheet); | |
} |
2. 任务栏和网格线的款式调整
(通过甘特图插件实现的任务栏和网格线的款式)
JavaScript 代码:
/*REPLACE_MARKER*/ | |
/*DO NOT DELETE THESE COMMENTS*/ | |
var myTable; | |
var ganttSheet; | |
window.onload = function() {var spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"), {sheetCount: 0}); | |
initSpread(spread); | |
initSplitView(spread); | |
}; | |
function initSpread(spread) {spread.suspendPaint(); | |
initDataSource(spread); | |
initGanttSheet(spread); | |
spread.resumePaint();} | |
function initDataSource(spread) { | |
var tableName = "Gantt_Id"; | |
var baseApiUrl = getBaseApiUrl(); | |
var apiUrl = baseApiUrl + "/" + tableName; | |
var dataManager = spread.dataManager(); | |
myTable = dataManager.addTable("myTable", { | |
batch: true, | |
remote: { | |
read: {url: apiUrl} | |
}, | |
schema: { | |
hierarchy: { | |
type: "Parent", | |
column: "parentId" | |
}, | |
columns: {id: { isPrimaryKey: true}, | |
taskNumber: {dataType: "rowOrder"} | |
} | |
} | |
}); | |
} | |
function initGanttSheet(spread) {ganttSheet = spread.addSheetTab(0, "GanttSheet", GC.Spread.Sheets.SheetType.ganttSheet); | |
var view = myTable.addView("ganttView", [{ value: "taskNumber", caption: "NO.", width: 60}, | |
{value: "name", caption: "Task Name", width: 200}, | |
{value: "duration", caption: "Duration", width: 90}, | |
{value: "predecessors", caption: "Predecessors", width: 120, visible: false} | |
]); | |
view.fetch().then(function() {ganttSheet.bindGanttView(view); | |
ganttSheet.project.timescale.tierMode = GC.Spread.Sheets.GanttSheet.TimescaleTierMode.topMiddleBottom; | |
ganttSheet.project.timescale.topTier.unit = GC.Spread.Sheets.GanttSheet.TimescaleUnit.thirdsOfMonth; | |
}).then(function() { | |
ganttSheet.gridlines.bottomTierColumn = { | |
lineType: GC.Spread.Sheets.GanttSheet.GanttGridlineType.dashed, | |
lineColor: "#c85b11" | |
}; | |
ganttSheet.gridlines.ganttRows.lineType = GC.Spread.Sheets.GanttSheet.GanttGridlineType.thin; | |
ganttSheet.gridlines.ganttRows.lineColor = "#abd08f"; | |
ganttSheet.gridlines.ganttRows.interval = 2; | |
ganttSheet.gridlines.ganttRows.intervalLineType = GC.Spread.Sheets.GanttSheet.GanttGridlineType.dashDot; | |
ganttSheet.gridlines.ganttRows.intervalLineColor = "#9cc3e5"; | |
}); | |
initSidePanel(ganttSheet); | |
} | |
function initSidePanel(ganttSheet) {var setButton = document.getElementById("set-gridline"); | |
var intervalPanel = document.getElementById("interval-panel"); | |
var affectItemOption = document.getElementById("affectItem"); | |
var lineTypeOption = document.getElementById("lineType"); | |
var lineColorOption = document.getElementById("lineColor"); | |
var intervalLineTypeOption = document.getElementById("intervalLineType"); | |
var intervalLineColorOption = document.getElementById("intervalLineColor"); | |
var intervalOption = document.getElementById("interval"); | |
var option = convertToNormalOptions(ganttSheet, "ganttRows"); | |
syncOptionToPanel(option); | |
affectItemOption.addEventListener('change', function(e) { | |
var target = affectItemOption.value; | |
if (affectItemOption.value === "ganttRows") {intervalPanel.classList.remove("hide"); | |
} else {intervalPanel.classList.add("hide"); | |
} | |
var option = convertToNormalOptions(ganttSheet, target); | |
syncOptionToPanel(option); | |
}); | |
setButton.addEventListener('click', function() { | |
var target = affectItemOption.value; | |
var lineType = Number(lineTypeOption.value); | |
var lineColor = lineColorOption.value; | |
var intervalLineType = Number(intervalLineTypeOption.value); | |
var intervalLineColor = intervalLineColorOption.value; | |
var interval = Number(intervalOption.value); | |
var option = convertToGanttGridlineOptions(lineType, lineColor, intervalLineType, intervalLineColor, interval); | |
if (option) {ganttSheet.gridlines[target] = option; | |
} | |
}); |
3. 数据展现布局调整
(通过甘特图插件实现布局的调整)
JavaScript 代码:
/*REPLACE_MARKER*/ | |
/*DO NOT DELETE THESE COMMENTS*/ | |
var myTable; | |
var ganttSheet; | |
var roundBarsToWholeDays = true; | |
window.onload = function() {var spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"), {sheetCount: 0}); | |
initSpread(spread); | |
initSplitView(spread); | |
}; | |
function initSpread(spread) {spread.suspendPaint(); | |
initDataSource(spread); | |
initGanttSheet(spread); | |
spread.resumePaint();} | |
function initDataSource(spread) { | |
var tableName = "Gantt_Id"; | |
var baseApiUrl = getBaseApiUrl(); | |
var apiUrl = baseApiUrl + "/" + tableName; | |
var dataManager = spread.dataManager(); | |
myTable = dataManager.addTable("myTable", { | |
batch: true, | |
remote: { | |
read: {url: apiUrl} | |
}, | |
schema: { | |
hierarchy: { | |
type: "Parent", | |
column: "parentId" | |
}, | |
columns: {id: { isPrimaryKey: true}, | |
taskNumber: {dataType: "rowOrder"} | |
} | |
} | |
}); | |
} | |
function initGanttSheet(spread) {ganttSheet = spread.addSheetTab(0, "GanttSheet", GC.Spread.Sheets.SheetType.ganttSheet); | |
var view = myTable.addView("ganttView", [{ value: "taskNumber", caption: "NO.", width: 60}, | |
{value: "name", caption: "Task Name", width: 200}, | |
{value: "duration", caption: "Duration", width: 90}, | |
{value: "predecessors", caption: "Predecessors", width: 120, visible: false} | |
]); | |
view.fetch().then(function() {ganttSheet.bindGanttView(view); | |
ganttSheet.suspendPaint(); | |
var summaryStyleRule = ganttSheet.project.taskStyleRules.getRule("summary"); | |
var summaryStyle = summaryStyleRule.style.taskbarStyle; | |
summaryStyle.leftText = "start"; | |
summaryStyle.rightText = "finish"; | |
summaryStyleRule.style.taskbarStyle = summaryStyle; | |
var layout = ganttSheet.project.layout; | |
layout.linkLineMode = "noLinks"; | |
layout.barHeight = 18; | |
ganttSheet.resumePaint();}); | |
initSidePanel(ganttSheet); | |
} | |
function initSidePanel(ganttSheet) {var roundBarItem = document.getElementById("round-bar"); | |
var linkTypeItem = document.getElementById("link-type"); | |
var barHeightItem = document.getElementById("bar-height"); | |
var dateFormatItem = document.getElementById("date-format"); | |
var setLayoutItem = document.getElementById("set-layout"); | |
roundBarItem.addEventListener("click", function() {if (roundBarItem.classList.contains("active")) {roundBarItem.classList.remove("active"); | |
roundBarsToWholeDays = false; | |
} else {roundBarItem.classList.add("active"); | |
roundBarsToWholeDays = true; | |
} | |
}); | |
setLayoutItem.addEventListener("click", function() { | |
var layout = ganttSheet.project.layout; | |
ganttSheet.suspendPaint(); | |
layout.linkLineMode = linkTypeItem.value; | |
layout.barHeight = Number(barHeightItem.value); | |
layout.barTextDateFormat = dateFormatItem.value; | |
layout.roundBarsToWholeDays = roundBarsToWholeDays; | |
ganttSheet.resumePaint();}); | |
} |
4. 工作操作
(可在甘特图插件实现工作操作)
JavaScript 代码:
/*REPLACE_MARKER*/ | |
/*DO NOT DELETE THESE COMMENTS*/ | |
var myTable; | |
var ganttSheet; | |
var roundBarsToWholeDays = true; | |
window.onload = function () {var spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"), {sheetCount: 0}); | |
initSpread(spread); | |
initSplitView(spread); | |
}; | |
function initSpread(spread) {spread.suspendPaint(); | |
initDataSource(spread); | |
initGanttSheet(spread); | |
spread.resumePaint();} | |
function initDataSource(spread) { | |
var tableName = "Gantt_Id"; | |
var baseApiUrl = getBaseApiUrl(); | |
var apiUrl = baseApiUrl + "/" + tableName; | |
var dataManager = spread.dataManager(); | |
myTable = dataManager.addTable("myTable", { | |
batch: true, | |
remote: { | |
read: {url: apiUrl}, | |
batch: {url: apiUrl + "Collection"} | |
}, | |
schema: { | |
hierarchy: { | |
type: "Parent", | |
column: "parentId" | |
}, | |
columns: {id: { isPrimaryKey: true}, | |
taskNumber: {dataType: "rowOrder"} | |
} | |
} | |
}); | |
} | |
function initGanttSheet(spread) {ganttSheet = spread.addSheetTab(0, "GanttSheet", GC.Spread.Sheets.SheetType.ganttSheet); | |
var view = myTable.addView("ganttView", [{ value: "id", caption: "Id", width: 40}, | |
{value: "taskNumber", caption: "NO.", width: 60}, | |
{value: "name", caption: "Task Name", width: 200}, | |
{value: "duration", caption: "Duration", width: 90}, | |
{value: "predecessors", caption: "Predecessors", width: 120} | |
]); | |
view.fetch().then(function () {ganttSheet.bindGanttView(view); | |
}); | |
initSidePanel(ganttSheet); | |
} | |
function initSidePanel(ganttSheet) {var addTaskItem = document.getElementById("add-task"); | |
var addSummayItem = document.getElementById("add-summary"); | |
var addMilestoneItem = document.getElementById("add-milestone"); | |
var deleteItem = document.getElementById("delete-task"); | |
var indentTaskItem = document.getElementById("indent-task"); | |
var outdentTaskItem = document.getElementById("outdent-task"); | |
var linkTaskItem = document.getElementById("link-task"); | |
var unlinkTaskItem = document.getElementById("unlink-task"); | |
var submitItem = document.getElementById("submit-changes"); | |
var cancelItem = document.getElementById("cancel-changes"); | |
addTaskItem.addEventListener("click", function () {ganttSheet.suspendPaint() | |
addTask(); | |
ganttSheet.resumePaint();}); | |
addSummayItem.addEventListener("click", function () {ganttSheet.suspendPaint() | |
addSummary(); | |
ganttSheet.resumePaint();}); | |
addMilestoneItem.addEventListener("click", function () {ganttSheet.suspendPaint() | |
addMilestone(); | |
ganttSheet.resumePaint();}); | |
deleteItem.addEventListener("click", function () {ganttSheet.suspendPaint() | |
deleteTask(); | |
ganttSheet.resumePaint();}); | |
indentTaskItem.addEventListener("click", function () {ganttSheet.suspendPaint() | |
indentTask(); | |
ganttSheet.resumePaint();}); | |
outdentTaskItem.addEventListener("click", function () {ganttSheet.suspendPaint() | |
outdentTask(); | |
ganttSheet.resumePaint();}); | |
linkTaskItem.addEventListener("click", function () {ganttSheet.suspendPaint() | |
linkTask(); | |
ganttSheet.resumePaint();}); | |
unlinkTaskItem.addEventListener("click", function () {ganttSheet.suspendPaint() | |
unlinkTask(); | |
ganttSheet.resumePaint();}); | |
submitItem.addEventListener("click", function () {ganttSheet.submitChanges(); | |
}); | |
cancelItem.addEventListener("click", function () {ganttSheet.cancelChanges(); | |
}); | |
function addTask() { | |
var project = ganttSheet.project; | |
var selections = ganttSheet.getSelections(); | |
var insertedRow = Math.min(...selections.map(r => r.row), project.tasks.length) | |
var rowCount = selections.map(r => r.rowCount).reduce((pre, current) => {return pre + current}); | |
var taskData = createTaskDataList(rowCount, () => ({name: "< 新工作 >"})); | |
project.insertTasksByRow(insertedRow, taskData); | |
} | |
function addSummary() { | |
var project = ganttSheet.project; | |
var selectedRange = ganttSheet.getSelections()[0]; | |
var insertedRow = selectedRange.row; | |
var insertedTaskNumbers = ganttSheet.getTaskByRow(insertedRow).taskNumber || project.count; | |
var selectedTasks = getSelectedRowIndexes().map((row) => ganttSheet.getTaskByRow(row)).filter((row) => !!row); | |
if (selectedTasks.length == 0) {project.insertTasks(insertedTaskNumbers, [{ name: "< 新摘要工作 >"}, {name: "< 新工作 >"}]); | |
project.indentTasks(insertedTaskNumbers + 1); | |
} else {project.insertTasks(insertedTaskNumbers, { name: "< 新摘要工作 >"}, selectedTasks[0].level); | |
project.indentTasks(selectedTasks.map((t) => t.taskNumber)); | |
} | |
ganttSheet.setSelection(insertedRow, -1, 1, -1); | |
} | |
function addMilestone() { | |
var project = ganttSheet.project; | |
var selections = ganttSheet.getSelections(); | |
var rowCount = selections.map(r => r.rowCount).reduce((pre, current) => {return pre + current}); | |
var insertedRow = Math.min(...selections.map(r => r.row), project.tasks.length); | |
var taskData = createTaskDataList(rowCount, () => ({name: "< 新里程碑 >", duration: 0})); | |
project.insertTasksByRow(insertedRow, taskData); | |
ganttSheet.setSelection(insertedRow, -1, rowCount, -1); | |
} | |
function deleteTask() { | |
var project = ganttSheet.project; | |
var rowIds = getSelectedTaskNumbers(); | |
project.removeTasks(rowIds); | |
} | |
function indentTask() { | |
var project = ganttSheet.project; | |
var rowIds = getSelectedTaskNumbers(); | |
project.indentTasks(rowIds); | |
} | |
function outdentTask() { | |
var project = ganttSheet.project; | |
var rowIds = getSelectedTaskNumbers(); | |
project.outdentTasks(rowIds); | |
} | |
function linkTask() { | |
var project = ganttSheet.project; | |
var links = []; | |
var selections = ganttSheet.getSelections(); | |
var previous = -1; | |
for (var range of selections) {if (previous != -1) {links.push([previous, range.row]); | |
} | |
for (var row = range.row + 1; row < range.row + range.rowCount; row++) {links.push([row - 1, row]); | |
} | |
previous = range.row + range.rowCount - 1; | |
} | |
if (links.length <= 0) {return;} | |
project.suspendSchedule(); | |
for (var link of links) {var [fromTaskNumber, toTaskNumber] = link; | |
try {project.addDependency({ fromTaskNumber, toTaskNumber}); | |
} catch {}} | |
project.resumeSchedule();} |
5. 日历
(可在甘特图插件内实现日历内容的调整)
JavaScript 代码:
/*REPLACE_MARKER*/ | |
/*DO NOT DELETE THESE COMMENTS*/ | |
var myTable; | |
var ganttSheet; | |
var roundBarsToWholeDays = true; | |
window.onload = function () {var spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"), {sheetCount: 0}); | |
initSpread(spread); | |
initSplitView(spread); | |
}; | |
function initSpread(spread) {spread.suspendPaint(); | |
initDataSource(spread); | |
initGanttSheet(spread); | |
spread.resumePaint();} | |
function initGanttSheet(spread) {ganttSheet = spread.addSheetTab(0, "GanttSheet", GC.Spread.Sheets.SheetType.ganttSheet); | |
var view = myTable.addView("ganttView", [{ value: "id", caption: "Id", width: 40}, | |
{value: "taskNumber", caption: "NO.", width: 60}, | |
{value: "name", caption: "Task Name", width: 200}, | |
{value: "duration", caption: "Duration", width: 90}, | |
{value: "predecessors", caption: "Predecessors", width: 120} | |
]); | |
view.fetch().then(function () {ganttSheet.bindGanttView(view); | |
}); | |
initSidePanel(ganttSheet); | |
} | |
function initSidePanel(ganttSheet) {var addTaskItem = document.getElementById("add-task"); | |
var addSummayItem = document.getElementById("add-summary"); | |
var addMilestoneItem = document.getElementById("add-milestone"); | |
var deleteItem = document.getElementById("delete-task"); | |
var indentTaskItem = document.getElementById("indent-task"); | |
var outdentTaskItem = document.getElementById("outdent-task"); | |
var linkTaskItem = document.getElementById("link-task"); | |
var unlinkTaskItem = document.getElementById("unlink-task"); | |
var submitItem = document.getElementById("submit-changes"); | |
var cancelItem = document.getElementById("cancel-changes"); | |
addTaskItem.addEventListener("click", function () {ganttSheet.suspendPaint() | |
addTask(); | |
ganttSheet.resumePaint();}); | |
addSummayItem.addEventListener("click", function () {ganttSheet.suspendPaint() | |
addSummary(); | |
ganttSheet.resumePaint();}); | |
addMilestoneItem.addEventListener("click", function () {ganttSheet.suspendPaint() | |
addMilestone(); | |
ganttSheet.resumePaint();}); | |
deleteItem.addEventListener("click", function () {ganttSheet.suspendPaint() | |
deleteTask(); | |
ganttSheet.resumePaint();}); | |
indentTaskItem.addEventListener("click", function () {ganttSheet.suspendPaint() | |
indentTask(); | |
ganttSheet.resumePaint();}); | |
outdentTaskItem.addEventListener("click", function () {ganttSheet.suspendPaint() | |
outdentTask(); | |
ganttSheet.resumePaint();}); | |
linkTaskItem.addEventListener("click", function () {ganttSheet.suspendPaint() | |
linkTask(); | |
ganttSheet.resumePaint();}); | |
unlinkTaskItem.addEventListener("click", function () {ganttSheet.suspendPaint() | |
unlinkTask(); | |
ganttSheet.resumePaint();}); | |
submitItem.addEventListener("click", function () {ganttSheet.submitChanges(); | |
}); | |
cancelItem.addEventListener("click", function () {ganttSheet.cancelChanges(); | |
}); | |
function addTask() { | |
var project = ganttSheet.project; | |
var selections = ganttSheet.getSelections(); | |
var insertedRow = Math.min(...selections.map(r => r.row), project.tasks.length) | |
var rowCount = selections.map(r => r.rowCount).reduce((pre, current) => {return pre + current}); | |
var taskData = createTaskDataList(rowCount, () => ({name: "< 新工作 >"})); | |
project.insertTasksByRow(insertedRow, taskData); | |
} | |
function addSummary() { | |
var project = ganttSheet.project; | |
var selectedRange = ganttSheet.getSelections()[0]; | |
var insertedRow = selectedRange.row; | |
var insertedTaskNumbers = ganttSheet.getTaskByRow(insertedRow).taskNumber || project.count; | |
var selectedTasks = getSelectedRowIndexes().map((row) => ganttSheet.getTaskByRow(row)).filter((row) => !!row); | |
if (selectedTasks.length == 0) {project.insertTasks(insertedTaskNumbers, [{ name: "< 新摘要工作 >"}, {name: "< 新工作 >"}]); | |
project.indentTasks(insertedTaskNumbers + 1); | |
} else {project.insertTasks(insertedTaskNumbers, { name: "< 新摘要工作 >"}, selectedTasks[0].level); | |
project.indentTasks(selectedTasks.map((t) => t.taskNumber)); | |
} | |
ganttSheet.setSelection(insertedRow, -1, 1, -1); | |
} | |
function addMilestone() { | |
var project = ganttSheet.project; | |
var selections = ganttSheet.getSelections(); | |
var rowCount = selections.map(r => r.rowCount).reduce((pre, current) => {return pre + current}); | |
var insertedRow = Math.min(...selections.map(r => r.row), project.tasks.length); | |
var taskData = createTaskDataList(rowCount, () => ({name: "< 新里程碑 >", duration: 0})); | |
project.insertTasksByRow(insertedRow, taskData); | |
ganttSheet.setSelection(insertedRow, -1, rowCount, -1); | |
} | |
function deleteTask() { | |
var project = ganttSheet.project; | |
var rowIds = getSelectedTaskNumbers(); | |
project.removeTasks(rowIds); | |
} | |
function indentTask() { | |
var project = ganttSheet.project; | |
var rowIds = getSelectedTaskNumbers(); | |
project.indentTasks(rowIds); | |
} | |
function outdentTask() { | |
var project = ganttSheet.project; | |
var rowIds = getSelectedTaskNumbers(); | |
project.outdentTasks(rowIds); | |
} | |
function linkTask() { | |
var project = ganttSheet.project; | |
var links = []; | |
var selections = ganttSheet.getSelections(); | |
var previous = -1; | |
for (var range of selections) {if (previous != -1) {links.push([previous, range.row]); | |
} | |
for (var row = range.row + 1; row < range.row + range.rowCount; row++) {links.push([row - 1, row]); | |
} | |
previous = range.row + range.rowCount - 1; | |
} | |
if (links.length <= 0) {return;} | |
project.suspendSchedule(); | |
for (var link of links) {var [fromTaskNumber, toTaskNumber] = link; | |
try {project.addDependency({ fromTaskNumber, toTaskNumber}); | |
} catch {}} | |
project.resumeSchedule();} | |
function unlinkTask() { | |
var project = ganttSheet.project; | |
var taskNumbers = getSelectedTaskNumbers(); | |
var dependencies = []; | |
if (taskNumbers.length == 1) {var task = project.getTaskByRow(taskNumbers[0]); | |
dependencies = [...task.predecessorDependencies, ...task.successorDependencies]; | |
} else {var taskNumberSet = {}; | |
for (var taskNumber of taskNumbers) {taskNumberSet[taskNumber] = true; | |
} | |
dependencies = project.dependencies.filter(dp => taskNumberSet[dp.from.taskNumber] && taskNumberSet[dp.to.taskNumber]); | |
} | |
if (dependencies.length >= 1) {project.removeDependency(dependencies); | |
} | |
} | |
function getSelectedRowIndexes() {var rows = []; | |
var selections = ganttSheet.getSelections(); | |
for (var range of selections) {for (var row = range.row; row < range.row + range.rowCount; row++) {rows.push(row); | |
} | |
} | |
return rows; | |
} |
6. 导入和导出操作
甘特图插件中展现的内容导出至 PDF 及 Excel 的格局。
(反对导入导出能力)
JavaScript 代码:
/*REPLACE_MARKER*/ | |
/*DO NOT DELETE THESE COMMENTS*/ | |
var myTable; | |
var ganttSheet; | |
var roundBarsToWholeDays = true; | |
window.onload = function() {var spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"), {sheetCount: 0}); | |
initSpread(spread); | |
initSplitView(spread); | |
}; | |
function initSpread(spread) {spread.suspendPaint(); | |
initDataSource(spread); | |
initGanttSheet(spread); | |
spread.resumePaint();} | |
function initDataSource(spread) { | |
var tableName = "Gantt_Id"; | |
var baseApiUrl = getBaseApiUrl(); | |
var apiUrl = baseApiUrl + "/" + tableName; | |
var dataManager = spread.dataManager(); | |
myTable = dataManager.addTable("myTable", { | |
batch: true, | |
remote: { | |
read: {url: apiUrl} | |
}, | |
schema: { | |
hierarchy: { | |
type: "Parent", | |
column: "parentId" | |
}, | |
columns: {id: { isPrimaryKey: true}, | |
taskNumber: {dataType: "rowOrder"} | |
} | |
} | |
}); | |
} | |
function initGanttSheet(spread) {ganttSheet = spread.addSheetTab(0, "GanttSheet", GC.Spread.Sheets.SheetType.ganttSheet); | |
var view = myTable.addView("ganttView", [{ value: "taskNumber", caption: "NO.", width: 60}, | |
{value: "name", caption: "Task Name", width: 200}, | |
{value: "duration", caption: "Duration", width: 90}, | |
{value: "predecessors", caption: "Predecessors", width: 120, visible: false} | |
]); | |
view.fetch().then(function() {ganttSheet.bindGanttView(view); | |
}); | |
initSidePanel(spread, ganttSheet); | |
} | |
function initSidePanel(spread, ganttSheet) {var excelIo = new GC.Spread.Excel.IO(); | |
var fileInput = document.getElementById("file-input"); | |
var openFileItem = document.getElementById("open-file"); | |
var fileNameItem = document.getElementById("file-name"); | |
var exportJSONItem = document.getElementById("export-to-json"); | |
var exportSJSItem = document.getElementById("export-to-sjs"); | |
var exportExcelItem = document.getElementById("export-to-excel"); | |
var printItem = document.getElementById("print"); | |
var pdfItem = document.getElementById("pdf"); | |
var exportFileName = "export"; | |
openFileItem.addEventListener('click', function() {fileInput.click(); | |
}); | |
fileInput.addEventListener('change', function(e) { | |
fileNameItem.value = 'Loading file...'; | |
var file = fileInput.files[0]; | |
if (!file) {alert("Upload a file first."); | |
return; | |
} | |
var fileName = file.name; | |
var suffix = fileName.substr(fileName.lastIndexOf('.')); | |
if (suffix === '.xlsx' || suffix === '.xlsm') { | |
// here is excel IO API | |
excelIo.open(file, function(json) {spread.fromJSON(json); | |
fileNameItem.value = fileName; | |
fileInput.value = ''; | |
}, function(e) { | |
// process error | |
console.log(e); | |
}); | |
} else if (suffix === '.ssjson' || suffix === '.json') {var reader = new FileReader(); | |
reader.onload = function() {var spreadJson = JSON.parse(this.result); | |
spread.fromJSON(spreadJson); | |
fileNameItem.value = fileName; | |
fileInput.value = ''; | |
}; | |
reader.readAsText(file); | |
} else if (suffix === '.sjs') {spread.open(file, () => { | |
fileNameItem.value = fileName; | |
fileInput.value = ''; | |
}, (e) => {console.log(e); | |
}, { | |
openMode: GC.Spread.Sheets.OpenMode.normal, | |
fullRecalc: true, | |
}); | |
} | |
}); | |
exportJSONItem.addEventListener('click', function () { | |
var fileName = exportFileName + ".ssjson"; | |
var json = spread.toJSON(); | |
saveAs(new Blob([JSON.stringify(json)], {type: "text/plain;charset=utf-8"}), fileName); | |
}); | |
exportSJSItem.addEventListener('click', function () { | |
var fileName = exportFileName + ".sjs"; | |
spread.save(function (blob) {saveAs(blob, fileName); | |
}, function (e) { | |
// process error | |
console.log(e); | |
}, { | |
fileType: GC.Spread.Sheets.FileType.ssjson, | |
includeBindingSource: true, | |
saveAsView: true | |
}); | |
}); | |
exportExcelItem.addEventListener('click', function () { | |
var fileName = exportFileName + ".xlsx"; | |
var json = spread.toJSON({includeBindingSource: true, saveAsView: true}); | |
// here is excel IO API | |
excelIo.save(json, function(blob) {saveAs(blob, fileName); | |
}, function(e) { | |
// process error | |
console.log(e); | |
}, {xlsxStrictMode: false}); | |
}); | |
printItem.addEventListener('click', function() {spread.print(); | |
}); | |
pdfItem.addEventListener('click', function() {spread.savePDF(function (blob) {var url = URL.createObjectURL(blob); | |
pwin = window.open(url); | |
}); | |
}); | |
} |
总结
甘特图是一种弱小的项目管理工具,通过直观的时间轴展现工作的安顿和进度。它能帮忙项目经理们创立具体的我的项目打算,无效跟踪进度,并正当分配资源。甘特图还能够治理工作间的依赖关系,及时调整时间表,并辨认危险与要害门路。它在项目管理中扮演着重要的角色,进步了团队的合作效率和我的项目的成功率。通过应用甘特图,我的项目团队可能更好地把握我的项目停顿,作出决策,并确保我的项目按时交付。
如果您对该插件感兴趣,能够拜访葡萄城官网下载 SpreadJS 产品。