如何使我的 Google Apps 脚本 运行 更快地用于电子表格多色甘特图?
How to make my Google Apps script run faster for spreadsheet multi-color gantt-chart?
我正在将 google sheet 的列和行格式化成一个大甘特图 chart.This 图表是为了显示每个员工为每个项目占用了多少周。每个人都有一个独特的颜色条。颜色条的位置和长度基于项目的开始周和持续时间。我创建了一个 "Update All" 按钮并将函数 update_all() 分配给该按钮。一旦我 运行 这个函数,我想要更新所有的颜色条。
我的脚本运行正常。但是,更新 70 行需要 40 秒,这使得它很难扩展到更大的员工组。耗时最长的操作是将单元格的背景颜色设置为员工指定的颜色。关于如何改进脚本以使其更快的任何建议?
这是甘特图的样子 -- goole sheet 文件
https://docs.google.com/spreadsheets/d/1nvnZB62CYUeUUZSkAuHsxMJF5MBr7D1rNG3ffU8jKdI/edit?usp=sharing
这是我的代码
function updateall(){
var sss = SpreadsheetApp.openById("1nvnZB62CYUeUUZSkAuHsxMJF5MBr7D1rNG3ffU8jKdI");
var ssColor = sss.getSheetByName("2. Color Legend");
var ssPlanner = sss.getSheetByName("Project Planner");
// Step 1: clear all the orginal color
ssPlanner.getRange("I4:BU120").setBackground('#ffffff');
// Step 2: create a dictionay {staff name : coloe code}
var keycolumns = ssColor.getRange(3,2,16,1).getValues();
var data = ssColor.getRange(3,3,16,1).getValues();
var dict_data = {};
for (var keys in keycolumns) {
var key = keycolumns[keys];
dict_data[key] = data[keys];
}
Logger.log(dict_data["BBB"]);
//Step3:set background color for each row
for (var bRow=4; bRow<121; bRow++){
if (ssPlanner.getRange("E"+bRow).getValue()!=""){
var start = ssPlanner.getRange(bRow,7).getValue()-ssPlanner.getRange(3,9).getValue()+9;
var duration = ssPlanner.getRange(bRow,8).getValue();
ssPlanner.getRange(bRow,start,1,duration).setBackground(dict_data[ssPlanner.getRange(bRow,5).getValue()]);
}
}
}
我相信你的目标如下。
- 您想减少脚本的处理成本。
为此,这个答案怎么样?
修改点:
在您的脚本中,循环中使用了 getRange
、getValue
和 setBackground
。我认为在这种情况下,脚本的处理成本会很高。为了降低您的脚本成本,我想提出以下流程。在这次修改中,我在你的脚本中修改了Step3
。
- 检索
E3:I121
范围内的所有值。
getValues()
已使用。
- 使用检索到的值创建一个数组来放置颜色。
- 在这种情况下,您要设置的颜色使用的是您创建的
dict_data
。并且,没有颜色的单元格设置为null
。因此,在您的情况下,ssPlanner.getRange("I4:BU120").setBackground('#ffffff')
可能可以修改为 ssPlanner.getRange("I4:BU120").setBackground(null)
.
getRange
、getValue
和 setBackground
未使用。
- 使用创建的包含颜色代码的数组设置颜色。
setBackgrounds
被使用。
当上面的流程反映到你的脚本中时,它变成如下。
修改后的脚本:
当您的脚本修改时,请修改如下。
从:
//Step3:set background color for each row
for (var bRow=4; bRow<121; bRow++){
if (ssPlanner.getRange("E"+bRow).getValue()!=""){
var start = ssPlanner.getRange(bRow,7).getValue()-ssPlanner.getRange(3,9).getValue()+9;
var duration = ssPlanner.getRange(bRow,8).getValue();
ssPlanner.getRange(bRow,start,1,duration).setBackground(dict_data[ssPlanner.getRange(bRow,5).getValue()]);
}
}
到:
// Step3:set background color for each row
// 1. Retrieve all values from the range of `E3:I121`.
const values = ssPlanner.getRange("E3:I121").getValues();
const offset = values.shift()[4];
// 2. Create an array for putting the colors using the retrieved values.
const colors = values.reduce((ar, [e,f,g,h]) => {
let base = Array(65).fill(null);
if (e != "") Array.prototype.splice.apply(base, [g - offset, h].concat(Array(h).fill(dict_data[e][0])));
ar.push(base);
return ar;
}, []);
// 3. Set the colors using the created array including the color codes.
ssPlanner.getRange(4, 9, colors.length, colors[0].length).setBackgrounds(colors);
参考文献:
我正在将 google sheet 的列和行格式化成一个大甘特图 chart.This 图表是为了显示每个员工为每个项目占用了多少周。每个人都有一个独特的颜色条。颜色条的位置和长度基于项目的开始周和持续时间。我创建了一个 "Update All" 按钮并将函数 update_all() 分配给该按钮。一旦我 运行 这个函数,我想要更新所有的颜色条。
我的脚本运行正常。但是,更新 70 行需要 40 秒,这使得它很难扩展到更大的员工组。耗时最长的操作是将单元格的背景颜色设置为员工指定的颜色。关于如何改进脚本以使其更快的任何建议?
这是甘特图的样子 -- goole sheet 文件 https://docs.google.com/spreadsheets/d/1nvnZB62CYUeUUZSkAuHsxMJF5MBr7D1rNG3ffU8jKdI/edit?usp=sharing
这是我的代码
function updateall(){
var sss = SpreadsheetApp.openById("1nvnZB62CYUeUUZSkAuHsxMJF5MBr7D1rNG3ffU8jKdI");
var ssColor = sss.getSheetByName("2. Color Legend");
var ssPlanner = sss.getSheetByName("Project Planner");
// Step 1: clear all the orginal color
ssPlanner.getRange("I4:BU120").setBackground('#ffffff');
// Step 2: create a dictionay {staff name : coloe code}
var keycolumns = ssColor.getRange(3,2,16,1).getValues();
var data = ssColor.getRange(3,3,16,1).getValues();
var dict_data = {};
for (var keys in keycolumns) {
var key = keycolumns[keys];
dict_data[key] = data[keys];
}
Logger.log(dict_data["BBB"]);
//Step3:set background color for each row
for (var bRow=4; bRow<121; bRow++){
if (ssPlanner.getRange("E"+bRow).getValue()!=""){
var start = ssPlanner.getRange(bRow,7).getValue()-ssPlanner.getRange(3,9).getValue()+9;
var duration = ssPlanner.getRange(bRow,8).getValue();
ssPlanner.getRange(bRow,start,1,duration).setBackground(dict_data[ssPlanner.getRange(bRow,5).getValue()]);
}
}
}
我相信你的目标如下。
- 您想减少脚本的处理成本。
为此,这个答案怎么样?
修改点:
在您的脚本中,循环中使用了
getRange
、getValue
和setBackground
。我认为在这种情况下,脚本的处理成本会很高。为了降低您的脚本成本,我想提出以下流程。在这次修改中,我在你的脚本中修改了Step3
。- 检索
E3:I121
范围内的所有值。getValues()
已使用。
- 使用检索到的值创建一个数组来放置颜色。
- 在这种情况下,您要设置的颜色使用的是您创建的
dict_data
。并且,没有颜色的单元格设置为null
。因此,在您的情况下,ssPlanner.getRange("I4:BU120").setBackground('#ffffff')
可能可以修改为ssPlanner.getRange("I4:BU120").setBackground(null)
. getRange
、getValue
和setBackground
未使用。
- 在这种情况下,您要设置的颜色使用的是您创建的
- 使用创建的包含颜色代码的数组设置颜色。
setBackgrounds
被使用。
- 检索
当上面的流程反映到你的脚本中时,它变成如下。
修改后的脚本:
当您的脚本修改时,请修改如下。
从://Step3:set background color for each row
for (var bRow=4; bRow<121; bRow++){
if (ssPlanner.getRange("E"+bRow).getValue()!=""){
var start = ssPlanner.getRange(bRow,7).getValue()-ssPlanner.getRange(3,9).getValue()+9;
var duration = ssPlanner.getRange(bRow,8).getValue();
ssPlanner.getRange(bRow,start,1,duration).setBackground(dict_data[ssPlanner.getRange(bRow,5).getValue()]);
}
}
到:
// Step3:set background color for each row
// 1. Retrieve all values from the range of `E3:I121`.
const values = ssPlanner.getRange("E3:I121").getValues();
const offset = values.shift()[4];
// 2. Create an array for putting the colors using the retrieved values.
const colors = values.reduce((ar, [e,f,g,h]) => {
let base = Array(65).fill(null);
if (e != "") Array.prototype.splice.apply(base, [g - offset, h].concat(Array(h).fill(dict_data[e][0])));
ar.push(base);
return ar;
}, []);
// 3. Set the colors using the created array including the color codes.
ssPlanner.getRange(4, 9, colors.length, colors[0].length).setBackgrounds(colors);