概述
本 Demo 展示了 SpreadJS 内置基本函数的使用方法。Demo 包含两个工作表:第一个工作表以学生成绩为例,演示如何使用 AVERAGE、MAX、MIN、MEDIAN 等统计函数计算平均分、最高分、最低分和中位数;第二个工作表展示了 Excel 2010 新增函数的使用示例。
实现思路
使用 setArray 方法批量加载学生成绩数据到工作表
使用 setArray 方法的第四个参数将公式数组批量设置到单元格
使用统计函数(AVERAGE、MAX、MIN、MEDIAN)计算各项统计数据
为平均分列添加三色条件格式,实现数据可视化效果
创建第二个工作表,展示 Excel 2010 新增函数的用法和结果
代码解析
批量设置学生成绩数据
setArray 方法将二维数组批量设置到工作表的指定位置。相比多次调用 setValue,setArray 在处理大量数据时性能更优。第一个参数 0 表示起始行索引,第二个参数 1 表示起始列索引。
批量设置统计公式
setArray 方法的第四个参数设为 true,表示数组中的字符串是公式而非普通文本。这样可以一次性将多个公式设置到单元格,避免多次调用 setFormula。AVERAGE 函数计算指定范围内数值的平均值。
计算各科统计数据
这段代码计算各科的统计数据:
MAX 函数:返回范围内的最大值
MIN 函数:返回范围内的最小值
MEDIAN 函数:返回范围内的中位数
添加三色条件格式
add3ScaleRule 方法为指定范围添加三色渐变条件格式:
minType、minValue、minColor:最小值的类型、值和颜色(红色)
midType、midValue、midColor:中间值的类型、值和颜色(白色)
maxType、maxValue、maxColor:最大值的类型、值和颜色(绿色)
ranges:应用条件的单元格范围数组
这里使用 ScaleValueType.lowestValue 表示最小值,ScaleValueType.percentile 表示第 50 百分位数(中位数),ScaleValueType.highestValue 表示最大值。条件格式会根据单元格值的大小,在红、白、绿三色之间渐变,直观展示成绩分布。
运行效果
第一个工作表显示学生成绩表,包含每位学生的五次作业成绩和自动计算的平均分
表格底部显示各科的统计数据:平均分、最高分、最低分和中位数
平均分列使用三色条件格式,分数越高颜色越绿,越低越红,中间值显示为白色
第二个工作表展示了多种 Excel 2010 新增函数(如 BETA.DIST、CHISQ.DIST、F.DIST 等)的使用示例和计算结果
双击公式单元格可查看完整公式,支持直接编辑和修改
API 参考
setArray 方法
row:起始行索引
column:起始列索引
array:要设置的二维数组
setFormula:可选,是否将数组中的字符串作为公式处理
conditionalFormats.add3ScaleRule 方法
minType:最小值类型(如 ScaleValueType.lowestValue)
minValue:最小值(某些类型可为 null)
minColor:最小值的颜色
midType:中间值类型(如 ScaleValueType.percentile)
midValue:中间值
midColor:中间值的颜色
maxType:最大值类型(如 ScaleValueType.highestValue)
maxValue:最大值(某些类型可为 null)
maxColor:最大值的颜色
ranges:应用范围的 Range 对象数组
window.onload = function () {
var spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"), { sheetCount: 2 });
initSpread(spread);
};
function initSpread(spread) {
var spreadNS = GC.Spread.Sheets;
var sheet = spread.getActiveSheet();
spread.suspendPaint();
var data = [
['五年级数学'],
['作业'],
['学生', 1, 2, 3, 4, 5, , '平均分'],
['Anna Mull', 76, 52, 91, 87, 98],
['Anna Sthesia', 95, 95, 94, 98, 95],
['Barb Ackue', 86, 83, 84, 89, 90],
['Barb Dwyer', 59, 40, 60, 20, 66],
['Barry Wine', 75, 55, 64, 76, 89],
['Bob Frapples', 91, 80, 72, 98, 95],
['Brock Lee', 86, 77, 89, 76, 70],
['Buck Kinnear', 100, 95, 94, 92, 91],
['Cliff Hanger', 97, 98, 99, 81, 89],
['Cory Ander', 53, 69, 93, 60, 95],
[''],
['平均分:'],
['最高分:'],
['最低分:'],
['中位数分数:'],
];
var formulas_r = [
['=AVERAGE(C4:G4)'],
['=AVERAGE(C5:G5)'],
['=AVERAGE(C6:G6)'],
['=AVERAGE(C7:G7)'],
['=AVERAGE(C8:G8)'],
['=AVERAGE(C9:G9)'],
['=AVERAGE(C10:G10)'],
['=AVERAGE(C11:G11)'],
['=AVERAGE(C12:G12)'],
['=AVERAGE(C13:G13)']
];
var formulas_b = [
['=AVERAGE(C4:C13)', '=AVERAGE(D4:D13)', '=AVERAGE(E4:E13)', '=AVERAGE(F4:F13)', '=AVERAGE(G4:G13)'],
['=MAX(C4:C13)', '=MAX(D4:D13)', '=MAX(E4:E13)', '=MAX(F4:F13)', '=MAX(G4:G13)'],
['=MIN(C4:C13)', '=MIN(D4:D13)', '=MIN(E4:E13)', '=MIN(F4:F13)', '=MIN(G4:G13)'],
['=MEDIAN(C4:C13)', '=MEDIAN(D4:D13)', '=MEDIAN(E4:E13)', '=MEDIAN(F4:F13)', '=MEDIAN(G4:G13)'],
];
sheet.setArray(0, 1, data);
sheet.setArray(3, 8, formulas_r, true);
sheet.setArray(14, 2, formulas_b, true);
sheet.setRowHeight(0, 40);
sheet.getCell(0, 1).font('Bold 19px Arial').vAlign(spreadNS.VerticalAlign.center);
sheet.addSpan(1, 1, 1, 8);
sheet.getCell(1, 1).font('Bold 13px Arial')
.hAlign(spreadNS.HorizontalAlign.center)
.backColor('rgb(130, 188, 0)')
.foreColor('white')
.vAlign(spreadNS.VerticalAlign.center);
sheet.getRange(2, 1, 1, 8).font('Bold 13px Arial')
.backColor('rgb(244, 248, 235)')
.vAlign(spreadNS.VerticalAlign.center)
.borderBottom(new spreadNS.LineBorder('black', spreadNS.LineStyle.thin));
sheet.getCell(2, 8).hAlign(spreadNS.HorizontalAlign.right);
sheet.getRange(3, 1, 10, 8).font('12px Arial');
sheet.getRange(14, 1, 4, 8).backColor('rgb(230,230,230)');
sheet.getRange(14, 1, 4, 1).font('Bold 12px Arial').hAlign(spreadNS.HorizontalAlign.right);
[110, 70, 70, 70, 70, 70, 10, 80].forEach(function (val, index) {
sheet.setColumnWidth(index + 1, val);
});
sheet.conditionalFormats.add3ScaleRule(
spreadNS.ConditionalFormatting.ScaleValueType.lowestValue, null, 'rgb(231,114,111)',
spreadNS.ConditionalFormatting.ScaleValueType.percentile, 50, 'rgb(252,252,255)',
spreadNS.ConditionalFormatting.ScaleValueType.highestValue, null, 'rgb(122,188,129)',
[new GC.Spread.Sheets.Range(3, 8, 10, 1)]);
spread.resumePaint();
initExcel2010(spread);
};
function initExcel2010(spread) {
var spreadNS = GC.Spread.Sheets;
var sheet = spread.getSheet(1);
sheet.name("Excel 2010 函数");
sheet.setColumnWidth(0, 200);
sheet.setColumnWidth(1, 400);
sheet.setColumnWidth(2, 80);
sheet.getRange(-1, 0, -1, 1).wordWrap(true);
sheet.getRange(-1, 1, -1, 1).wordWrap(true);
let data = [
["公式", "描述", "结果"],
["=BETA.DIST(2,8,10,TRUE,1,3)", "累积贝塔概率密度函数"],
["=BETA.DIST(2,8,10,FALSE,1,3)", "贝塔概率密度函数"],
["=CEILING.PRECISE(4.3)", "将 4.3 向上舍入到最接近的 1 的倍数。"],
["=CEILING.PRECISE(-4.3)", "将 -4.3 向上舍入到最接近的 1 的倍数。由于数字为负,因此向 0 舍入。"],
["=CEILING.PRECISE(4.3, 2)", "将 4.3 向上舍入到最接近的 2 的倍数。"],
["=CHISQ.DIST(0.5,1,TRUE)", "0.5 的卡方分布,返回为累积分布函数,使用 1 个自由度。"],
["=CHISQ.DIST(2,3,FALSE)", "2 的卡方分布,返回为概率密度函数,使用 3 个自由度。"],
["=CHISQ.INV(0.93,1)", "0.93 的卡方分布左尾概率的反函数,使用 1 个自由度。"],
["=CHISQ.INV(0.6,2)", "0.6 的卡方分布左尾概率的反函数,使用 2 个自由度。"],
["=CONFIDENCE.T(0.05,1,50)", "基于样本大小为 50、显著性水平为 5% 且标准差为 1 的总体均值的置信区间。这基于学生 t 分布。"],
["=COVARIANCE.S({2,4,8},{5,8,11})", "以数组形式输入到函数中的数据点的样本协方差。"],
["=ERF.PRECISE(0.74500)", "误差函数在 0 和 0.74500 之间的积分 (0.707929)"],
["=ERFC.PRECISE(0.74500)", "0.74500 的互补误差函数。"],
["=F.DIST(15.2069,6,4,TRUE)", "使用累积分布函数的 F 概率(累积参数为 TRUE)。"],
["=F.DIST(15.2069,6,4,FALSE)", "使用概率密度函数的 F 概率(累积参数为 FALSE)。"],
["=F.INV(0.01,6,4)", "F 概率分布的反函数。"],
["=FLOOR.PRECISE(-3.2)", "将 -3.2 向下舍入到最接近的 -1 的倍数"],
["=FLOOR.PRECISE(3.2)", "将 3.2 向下舍入到最接近的 1 的倍数"],
["=FLOOR.PRECISE(3.2, 2)", "将 3.2 向下舍入到最接近的 2 的倍数"],
["=GAMMALN.PRECISE(4)", "4 处的伽马函数的自然对数"],
["=HYPGEOM.DIST(1,4,8,20,TRUE)", "累积超几何分布函数。"],
["=HYPGEOM.DIST(1,4,8,20,FALSE)", "概率超几何分布函数。"],
["=ISO.CEILING(4.3)", "将 4.3 向上舍入到最接近的 1 的倍数"],
["=ISO.CEILING(-4.3)", "将 -4.3 向上舍入到最接近的 1 的倍数"],
["=ISO.CEILING(4.3, 2)", "将 4.3 向上舍入到最接近的 2 的倍数"],
["=LOGNORM.DIST(4,3.5,1.2,TRUE)", "4 处的累积对数正态分布。"],
["=LOGNORM.DIST(4,3.5,1.2,FALSE)", "4 处的概率对数正态分布。"],
["=NEGBINOM.DIST(10,5,0.25,TRUE)", "累积负二项分布。"],
["=NEGBINOM.DIST(10,5,0.25,FALSE)", "概率负二项分布。"],
["=NETWORKDAYS.INTL(DATE(2006,1,1),DATE(2006,1,31))", "结果为 22 个未来工作日。从两个日期之间的 31 天总数中减去 9 个非工作日(5 个星期六和 4 个星期日)。默认情况下,星期六和星期日被视为非工作日。"],
["=NETWORKDAYS.INTL(DATE(2006,2,28),DATE(2006,1,31))", "结果为 -21,即过去的 21 个工作日。"],
["=NETWORKDAYS.INTL(DATE(2006,1,1),DATE(2006,2,1),7,{\"2006/1/2\",\"2006/1/16\"})", "通过从 2006 年 1 月 1 日到 2006 年 2 月 1 日的 32 天中减去 10 个非工作日(4 个星期五、4 个星期六、2 个节假日),结果为 22 个未来工作日。使用参数 7 表示周末,即星期五和星期六。此时间段内还有两个节假日。"],
["=NETWORKDAYS.INTL(DATE(2006,1,1),DATE(2006,2,1),\"0010001\",{\"2006/1/2\",\"2006/1/16\"})", "结果为 20 个未来工作日。与上面的时间段相同,但星期日和星期三为周末。"],
["=NORM.S.DIST(1.333333,TRUE)", "1.333333 处的正态累积分布函数。"],
["=NORM.S.DIST(1.333333,FALSE)", "1.333333 处的正态概率分布函数。"],
["=PERCENTRANK.EXC({1,2,3,4,6,6,7,8,9}, 7)", "返回数组中值 7 的排名。"],
["=PERCENTRANK.EXC({1,2,3,4,6,6,7,8,9}, 5.43)", "返回数组中值 5.43 的排名。"],
["=PERCENTRANK.EXC({1,2,3,4,6,6,7,8,9}, 5.43, 1)", "返回数组中值 5.43 的排名,结果中仅显示 1 位有效数字(默认值为 3)。"],
["=PERCENTILE.EXC({1,2,3,4,5,6}, 0.25)", "当指定百分位数的值位于数组中的两个值之间时进行插值。"],
["=QUARTILE.EXC({1,2,3,4,5,6,7,8,9,10,11},1)", "定位第一个四分位数的位置 (3)。"],
["=QUARTILE.EXC({1,2,3,4,5,6,7,8,9,10,11},3)", "定位第三个四分位数的位置 (9)。"],
["=RANK.AVG(95, {89, 88, 92, 101, 94, 97, 95})", "查找数组中值 95 的排名(位置)(降序)。在这种情况下,95 在降序中排名第 3。"],
["=RANK.AVG(95, {89, 88, 92, 101, 94, 97, 95}, 1)", "查找数组中值 95 的排名(位置)(升序)。在这种情况下,95 在升序中排名第 5。"],
["=T.DIST(60,1,TRUE)", "60 的学生左尾 t 分布,返回为累积分布函数,使用 1 个自由度。"],
["=T.DIST(8,3,FALSE)", "8 的学生左尾 t 分布,返回为概率密度函数,使用 3 个自由度。"],
["=T.INV(0.05464,60)", "基于指定参数的学生 t 分布的 t 值。"],
["=WORKDAY.INTL(DATE(2012,1,1),30,0)", "周末参数使用 0 会导致 #NUM! 错误。"],
["=WORKDAY.INTL(DATE(2012,1,1),90,11)", "从 2012 年 1 月 1 日起找到 90 个工作日后的日期,仅将星期日视为周末(周末参数为 11)。"],
["=TEXT(WORKDAY.INTL(DATE(2012,1,1),30,17), \"m/dd/yyyy\")", "使用 TEXT 函数将结果序列号 (40944) 格式化为 \"m/dd/yyyy\" 格式。从 2012 年 1 月 1 日起找到 30 个工作日后的日期,仅将星期六视为周末(周末参数为 17)。"]
];
sheet.setArray(0, 0, data, false);
var r, len, i;
for (r = 1, len = data.length; r < len; r++) {
sheet.setFormula(r, 2, data[r][0]);
}
var arrayFormulaData = [
["=MODE.MULT({1,2,3,4,3,2,1,2,1,3})", "该公式必须作为数组公式输入。它返回 1、2 和 3 作为众数,因为它们各出现 3 次。如果该公式不作为数组公式输入,则单个结果为 1。", 3]
];
for (i = 0, len = arrayFormulaData.length; i < len; i++) {
var cur = arrayFormulaData[i],
rows = cur[2],
cols = cur[3] || 1;
sheet.addSpan(r, 0, rows, 1);
sheet.setValue(r, 0, cur[0]);
sheet.addSpan(r, 1, rows, 1);
sheet.setValue(r, 1, cur[1]);
sheet.setArrayFormula(r, 2, rows, cols, cur[0]);
r += rows;
}
for (i = 1; i < r; i++) {
sheet.autoFitRow(i);
}
sheet.getRange(-1, 2, -1, 1).formatter(".######");
sheet.setFormatter(48, 2, "M/d/yyyy");
var table = sheet.tables.add("FunctionTable", 0, 0, 50, 3, spreadNS.Tables.TableThemes.medium9);
table.rowFilter().filterButtonVisible(false);
// Array formula with merge cells, set style like above table rows
var rowStyle = sheet.getActualStyle(48, 0);
sheet.getRange(50, 0, 3, 3).backColor(rowStyle.backColor);
sheet.getRange(49, 0, 4, 3).setBorder(rowStyle.borderBottom, {
all: true
});
}
<!doctype html>
<html style="height:100%;font-size:14px;">
<head>
<meta name="spreadjs culture" content="zh-cn" />
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" type="text/css"
href="$DEMOROOT$/zh/purejs/node_modules/@grapecity-software/spread-sheets/styles/gc.spread.sheets.excel2013white.css">
<script src="$DEMOROOT$/zh/purejs/node_modules/@grapecity-software/spread-sheets/dist/gc.spread.sheets.all.min.js"
type="text/javascript"></script>
<script
src="$DEMOROOT$/zh/purejs/node_modules/@grapecity-software/spread-sheets-resources-zh/dist/gc.spread.sheets.resources.zh.min.js"
type="text/javascript"></script>
<script src="$DEMOROOT$/spread/source/js/license.js" type="text/javascript"></script>
<script src="app.js" type="text/javascript"></script>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body>
<div class="sample-tutorial">
<div id="ss" class="sample-spreadsheets"></div>
</div>
</body>
</html>
.sample-tutorial {
position: relative;
height: 100%;
overflow: hidden;
}
.sample-spreadsheets {
width: 100%;
height: 100%;
overflow: hidden;
float: left;
border: 1px solid gray;
}
body {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}