echarts热力图数据聚合

总结摘要
echarts热力图数据聚合

问题

echarts热力图渲染数据超过2万会感觉明显卡顿

解决办法

后端通过网格将数据聚合,压缩数据量

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
// 网格聚合核心方法
public static JSONArray gridAggregate(JSONArray points, int xGridSize, int yGridSize) throws JSONException {

    if(points.size() <= 20000){
        return points;
    }

    // 1. 计算坐标范围
    double minX = 0, maxX = 0, minY = 0, maxY = 0;

    for (int i = 0; i < points.size(); i++) {
        JSONArray point = points.getJSONArray(i);
        double x = point.getDouble(0);
        double y = point.getDouble(1);
        if(i == 0){
            minX = x;
            maxX = x;
            minY = y;
            maxY = y;
        }else{
            minX = Math.min(minX, x);
            maxX = Math.max(maxX, x);
            minY = Math.min(minY, y);
            maxY = Math.max(maxY, y);
        }
    }

    // 2. 初始化网格容器 (使用网格坐标作为Key)
    TreeMap<String, List<Double>> gridMap = new TreeMap<>();
    double gridWidth = (maxX - minX) / xGridSize;
    double gridHeight = (maxY - minY) / yGridSize;

    // 3. 点分配到网格
    for (int i = 0; i < points.size(); i++) {
        JSONArray point = points.getJSONArray(i);
        double x = point.getDouble(0);
        double y = point.getDouble(1);
        double value = point.getDouble(2);

        int gridX = (int) ((x - minX) / gridWidth);
        int gridY = (int) ((y - minY) / gridHeight);
        String gridKey = gridX + "_" + gridY;

        gridMap.computeIfAbsent(gridKey, k -> new ArrayList<>()).add(value);
    }

    // 4. 生成聚合数据 (使用平均值策略)
    JSONArray aggregatedData = new JSONArray();
    for (Map.Entry<String, List<Double>> entry : gridMap.entrySet()) {
        String[] keys = entry.getKey().split("_");
        int gridX = Integer.parseInt(keys[0]);
        int gridY = Integer.parseInt(keys[1]);

        // 计算网格中心坐标
        double centerX = minX + (gridX + 0.5) * gridWidth;
        double centerY = minY + (gridY + 0.5) * gridHeight;

        // 计算平均值
        double avgValue = entry.getValue().stream()
                .mapToDouble(Double::doubleValue)
                .average()
                .orElse(0.0);

        // 构建新数据点 [x, y, value]
        JSONArray newPoint = new JSONArray();
        newPoint.put(new BigDecimal(centerX).setScale(2, RoundingMode.DOWN).intValue());
        newPoint.put(new BigDecimal(centerY).setScale(2, RoundingMode.DOWN).doubleValue());
        newPoint.put(new BigDecimal(avgValue).setScale(6, RoundingMode.DOWN).doubleValue());

        aggregatedData.put(newPoint);
    }

    //System.out.println("原始点数: " + points.size());
    //System.out.println("聚合后点数: " + aggregatedData.size());

    aggregatedData.sort((o1, o2) -> {
        JSONArray points1 = (JSONArray) o1;
        JSONArray points2 = (JSONArray) o2;
        return points1.getInt(0).compareTo(points2.getInt(0));
    });

    return aggregatedData;
}