【分享】自定义函数实现列数据渐变背景色填充

需求说明

在润乾报表中,对自动扩展的单元格区域,设置三种基础背景色,使扩展后的单元格自动填充出平滑的渐变色背景。

ScreenShot_20260212_143923_755png

实现方法

自定义函数,通过动态计算颜色值并设置单元格背景色表达式引用该函数,实现渐变效果。

实现步骤

1、自定义函数
具体代码为:

import com.raqsoft.common.ReportError;
import com.raqsoft.report.model.expression.Expression;
import com.raqsoft.report.model.expression.Function;
import com.raqsoft.report.model.expression.Variant2;
import com.raqsoft.report.resources.EngineMessage;
import com.raqsoft.report.usermodel.Context;
import com.scudata.common.MessageManager;

public class JJS  extends Function{

	@Override
	public Object calculate(Context ctx) {
		// TODO Auto-generated method stub
		verifyBlackColor();
		
		 if (this.param == null || this.param.getSubSize() ==0) { // 判断参数是否为空
			 MessageManager mm = EngineMessage.get();
			  throw new ReportError("encrypt:" + mm.getMessage("function.invalidParam"));
			  }
	     // 获取第一个参数的表达式,从 0 开始
		Expression param1=(Expression)this.param.getSub(0).getLeafExpression();   
		// 算出第一个参数值
		int totalL = (int) Variant2.getValue(param1.calculate(ctx),false);			  

	    // 获取第二个参数的表达式
		Expression param2=(Expression)this.param.getSub(1).getLeafExpression();   
		// 算出第二个参数值
	    int indexL = (int) Variant2.getValue(param2.calculate(ctx),false);
	    return getGradientColor(totalL,indexL);
		//return null;
	}
	// 生成优化后的渐变颜色(返回润乾兼容的带符号ARGB数值)
	public static int getGradientColor(int total, int index) {
		// 1. 定义三个基础色(RGB数组)
		//int[] colorA = new int[]{255, 107, 107}; // #FF6B6B
		//int[] colorB = new int[]{255, 255, 224};  // #4ECDC4
		//int[] colorC = new int[]{85, 98, 112};   // #556270
		
		//红 黄 橙
		int[] colorA = new int[]{178, 34, 34}; 
		int[] colorB = new int[]{78, 205, 196}; 
		int[] colorC = new int[]{255, 140, 0};   
		
		// 2. 边界处理(优化逻辑,保证基础色精准返回)
		if (total <= 1) {
			return getArgbColor(255, colorA[0], colorA[1], colorA[2]); 
		} else if (total == 2) {
			return index == 1 ? getArgbColor(255, colorA[0], colorA[1], colorA[2]) 
							  : getArgbColor(255, colorC[0], colorC[1], colorC[2]);
		}

		// 3. 优化的渐变区间计算(核心改进点)
		// 将整个渐变过程分为两段:A→B(前半段)、B→C(后半段),总长度为total-1个过渡步长
		double totalSteps = total - 1;
		// 计算当前索引对应的全局进度(0~1)
		double globalProgress = (index - 1) / totalSteps;
		
		double r, g, b;
		// 两段渐变的分界点设为0.5(中间位置)
		if (globalProgress <= 0.5) {
			// A→B渐变:将0~0.5的进度映射到0~1
			double segmentProgress = globalProgress / 0.5;
			// 使用线性插值+轻微的平滑处理
			segmentProgress = smoothStep(segmentProgress);
			r = linearInterpolation(colorA[0], colorB[0], segmentProgress);
			g = linearInterpolation(colorA[1], colorB[1], segmentProgress);
			b = linearInterpolation(colorA[2], colorB[2], segmentProgress);
		} else {
			// B→C渐变:将0.5~1的进度映射到0~1
			double segmentProgress = (globalProgress - 0.5) / 0.5;
			segmentProgress = smoothStep(segmentProgress);
			r = linearInterpolation(colorB[0], colorC[0], segmentProgress);
			g = linearInterpolation(colorB[1], colorC[1], segmentProgress);
			b = linearInterpolation(colorB[2], colorC[2], segmentProgress);
		}

		// 4. 四舍五入为整数RGB(限制取值范围,避免越界)
		int roundR = clamp(Math.round((float) r), 0, 255);
		int roundG = clamp(Math.round((float) g), 0, 255);
		int roundB = clamp(Math.round((float) b), 0, 255);

		// 5. 转换为润乾兼容的ARGB有符号数值
		return getArgbColor(255, roundR, roundG, roundB);
	}

// 线性插值方法(保证颜色过渡均匀)
private static double linearInterpolation(int start, int end, double progress) {
    return start + (end - start) * progress;
}

// 平滑步进函数(让渐变开头和结尾更柔和,避免生硬)
private static double smoothStep(double x) {
    // 使用3x²-2x³的平滑曲线,x∈[0,1]
    return x * x * (3 - 2 * x);
}

// 数值范围限制(防止RGB值超出0-255范围)
private static int clamp(int value, int min, int max) {
    return Math.max(min, Math.min(max, value));
}

// 核心工具方法:计算润乾格式的ARGB有符号数值
private static int getArgbColor(int a, int r, int g, int b) {
    int argb = (a << 24) | (r << 16) | (g << 8) | b;
    return argb;
}

// 辅助方法:验证润乾数值
public static void verifyBlackColor() {
    int blackArgb = getArgbColor(255, 0, 0, 0);
    //System.out.println("黑色的润乾数值(预期-16777216):" + blackArgb);
}
}

保存为 JJS.java。

2、在设计器下引入编写好的类文件
把写好的 JJS.java 编译后的.class 文件放到设计器的类路径下 report\config\classes(没有的文件夹自己新建),否则找不到这个类。
3、自定义函数的登记
在 java 的类路径 report\config\classes\config 下找到 customFunctions.properties 文件 (如果没有需要自己创建),并在其中进行自定义函数类及函数名的登记。
具体写法为:

# hello=0,func.TestFunc
# 0代表普通函数,1代表数据集函数

sim=0,com.raqsoft.report.selfdefine.SimFunction
dsfun=1,com.raqsoft.report.selfdefine.DsFun
jjs=0,JJS

4、设计报表

2png

在 B1 单元格引用 JJS()函数,写法为 jjs(A2,A1)
5、预览报表效果为

3png

6、web 端预览查看效果
将编译好的类文件以及自定义函数登记的文件放在 web 应用目录下。
JJS.java 、JJS.class 文件放在安装目录 report\web\webapps\demo\WEB-INF\classes 下
customFunctions.properties 文件放在 report\web\webapps\demo\WEB-INF\classes\config 下。

4png

示例报表
zip