You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于D3.js甘特图的告警数组扁平化与重构方案问询

D3.js甘特图告警数据最优重构方案

需求说明

开发D3.js甘特图时,需对告警数据集做以下处理:

  • 按starting_time/ending_time组成的时间区间扁平化数组,同一区间的条目合并为一条数据
  • 按type字段分组,重构text字段,同时生成符合要求的tooltip文本(鼠标悬停时展示(Device: pH, Humidity)(Report: Swelling)(Clinician Assessment: Pain Level)格式的分组信息)

原始数据

let array = [
{text: "pH", starting_time: 1693347129000, ending_time: 1693350729000, type: "device"},
{text: "humidity", starting_time: 1693347129000, ending_time: 1693350729000, type: "device"},
{text: "pH", starting_time: 1693339929000, ending_time: 1693343529000, type: "device"},
{text: "pH", starting_time: 1692958329000, ending_time: 1692961929000, type: "device"},
{text: "humidity", starting_time: 1692958329000, ending_time: 1692961929000, type: "device"},
{text: "pH", starting_time: 1692738729000, ending_time: 1692742329000, type: "device"},
{text: "humidity", starting_time: 1692738729000, ending_time: 1692742329000, type: "device"},
{text: "temperature", starting_time: 1692735129000, ending_time: 1692738729000, type: "device"},
{text: "pH", starting_time: 1692735129000, ending_time: 1692738729000, type: "device"},
{text: "humidity", starting_time: 1692213729000, ending_time: 1692217329000, type: "device"},
{text: "humidity", starting_time: 1692130929000, ending_time: 1692134529000, type: "device"},
{text: "pain level", starting_time: 1695972618000, ending_time: 1695976218000, type: "report"},
{text: "swelling", starting_time: 1695597028000, ending_time: 1695600628000, type: "report"},
{text: "level of pain", starting_time: 1695597028000, ending_time: 1695600628000, type: "clinicianAssessment"}
];

初步尝试代码

function alertBreakdown(result){
    let schedule = [...result];

    //flat all the dates to one array
    const timestamps = schedule.flatMap(_ => _.starting_time);

    //flatten also for ending_time? so if same starting/ending time?

    //console.log("timestamps", timestamps);

    //count the occurrences of each date in a dictionary structure
    const day2count = {};
    timestamps.forEach(timestamp => {
        //console.log("--<timestamp", timestamp);
        const day = moment(timestamp).format("YYYY-MM-DD");//.toString().split('T')[0];
        //const day = timestamp.toString().split('T')[0];
        day2count[day] = (day2count[day] || 0) + 1;
    });

    //console.log("day2count", day2count);
       
    // convert the map to an array of entries
    const scheduleResult = Object.entries(day2count).map(([date, value]) => ({date: moment(date), value: value, toolTipText: "test" }))
          .sort((a,b) => moment(a.date) - moment(b.date))

    return scheduleResult;

}

期望输出格式

let array = [
{text: "Device: pH, humidity", starting_time: 1693347129000, ending_time: 1693350729000, type: "device"},
{text: "Device: pH", starting_time: 1693339929000, ending_time: 1693343529000, type: "device"},
{text: "Device: pH, humidity", starting_time: 1692958329000, ending_time: 1692961929000, type: "device"},
{text: "Device: pH, humidity", starting_time: 1692738729000, ending_time: 1692742329000, type: "device"},
{text: "Device: temperature, pH", starting_time: 1692735129000, ending_time: 1692738729000, type: "device"},
{text: "Device: humidity", starting_time: 1692213729000, ending_time: 1692217329000, type: "device"},
{text: "Device: humidity", starting_time: 1692130929000, ending_time: 1692134529000, type: "device"},
{text: "Report: pain level", starting_time: 1695972618000, ending_time: 1695976218000, type: "report"},
{text: "Report: swelling, Clinician Assessment: level of pain", starting_time: 1695597028000, ending_time: 1695600628000, type: "report, clinicianAssement"},
];

最优数据重构方案

核心思路

  1. 按时间区间分组:用starting_time和ending_time的组合作为唯一键,将同一时间区间的所有条目聚合在一起
  2. 按type二次分组:在每个时间区间内,按type收集对应的text内容,同时处理type的友好显示名称(如clinicianAssessment转为Clinician Assessment)
  3. 生成格式化文本:根据分组结果,构建符合要求的text字段和tooltip文本
  4. 整理输出结构:将分组后的数据转换为期望的数组格式,同时保留时间区间信息

代码实现

// 定义type到友好名称的映射
const typeDisplayNameMap = {
  device: "Device",
  report: "Report",
  clinicianAssessment: "Clinician Assessment"
};

function refactorAlertData(originalData) {
  // 用时间区间作为键,聚合数据
  const intervalMap = {};

  originalData.forEach(item => {
    // 生成时间区间的唯一键:starting_time + "-" + ending_time
    const intervalKey = `${item.starting_time}-${item.ending_time}`;
    
    if (!intervalMap[intervalKey]) {
      // 初始化区间数据
      intervalMap[intervalKey] = {
        starting_time: item.starting_time,
        ending_time: item.ending_time,
        typeGroups: {} // 存储该区间下的type->texts映射
      };
    }

    const intervalData = intervalMap[intervalKey];
    // 按type收集text
    if (!intervalData.typeGroups[item.type]) {
      intervalData.typeGroups[item.type] = [];
    }
    intervalData.typeGroups[item.type].push(item.text);
  });

  // 将intervalMap转换为期望的数组格式
  return Object.values(intervalMap).map(intervalData => {
    // 生成text字段和tooltip文本
    const textSegments = [];
    const tooltipSegments = [];
    const types = [];

    // 遍历每个type分组
    Object.entries(intervalData.typeGroups).forEach(([type, texts]) => {
      const displayName = typeDisplayNameMap[type] || type;
      const joinedTexts = texts.join(", ");
      
      textSegments.push(`${displayName}: ${joinedTexts}`);
      tooltipSegments.push(`(${displayName}: ${joinedTexts})`);
      types.push(type);
    });

    return {
      text: textSegments.join(", "),
      starting_time: intervalData.starting_time,
      ending_time: intervalData.ending_time,
      type: types.join(", "),
      tooltipText: tooltipSegments.join("") // 额外生成tooltip专用文本,方便D3调用
    };
  }).sort((a, b) => a.starting_time - b.starting_time); // 按开始时间排序
}

// 使用示例
const refactoredArray = refactorAlertData(array);
console.log(refactoredArray);

方案优势

  • 时间复杂度为O(n),仅需遍历原始数据一次,再遍历分组后的结果一次,性能高效
  • 逻辑清晰,通过双层分组(时间区间→type)精准聚合数据
  • 扩展性强,新增type时只需在typeDisplayNameMap中添加映射即可
  • 额外生成tooltipText字段,直接满足D3.js悬停展示需求,无需后续二次处理

内容的提问来源于stack exchange,提问作者The Old County

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 10:17:34