313 lines
10 KiB
JavaScript
313 lines
10 KiB
JavaScript
// 定义数据资产路径树的数据结构
|
|
const treeData = {
|
|
name: "数据资产入表",
|
|
children: [
|
|
{
|
|
name: "数据采集",
|
|
description: "从各种来源收集原始数据",
|
|
children: [
|
|
{
|
|
name: "结构化数据",
|
|
description: "数据库、Excel等格式化数据",
|
|
children: [
|
|
{
|
|
name: "数据库抽取",
|
|
description: "使用ETL工具从数据库中抽取数据"
|
|
},
|
|
{
|
|
name: "文件导入",
|
|
description: "导入Excel、CSV等文件数据"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: "非结构化数据",
|
|
description: "文档、图片、视频等非结构化数据",
|
|
children: [
|
|
{
|
|
name: "文本解析",
|
|
description: "解析文档、日志等文本数据"
|
|
},
|
|
{
|
|
name: "媒体处理",
|
|
description: "处理图片、视频等媒体数据"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: "数据处理",
|
|
description: "对采集的数据进行清洗和转换",
|
|
children: [
|
|
{
|
|
name: "数据清洗",
|
|
description: "去除异常值和重复数据",
|
|
children: [
|
|
{
|
|
name: "质量检查",
|
|
description: "检查数据完整性和准确性"
|
|
},
|
|
{
|
|
name: "数据修复",
|
|
description: "修复和补充缺失数据"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: "数据转换",
|
|
description: "转换数据格式和结构",
|
|
children: [
|
|
{
|
|
name: "格式标准化",
|
|
description: "统一数据格式和编码"
|
|
},
|
|
{
|
|
name: "结构转换",
|
|
description: "调整数据结构以适应目标系统"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: "数据入表",
|
|
description: "将处理后的数据导入目标系统",
|
|
children: [
|
|
{
|
|
name: "数据映射",
|
|
description: "建立源数据和目标表的字段映射",
|
|
children: [
|
|
{
|
|
name: "字段匹配",
|
|
description: "确定源字段和目标字段的对应关系"
|
|
},
|
|
{
|
|
name: "转换规则",
|
|
description: "定义数据转换和计算规则"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: "数据加载",
|
|
description: "将数据加载到目标表中",
|
|
children: [
|
|
{
|
|
name: "增量更新",
|
|
description: "只更新变化的数据"
|
|
},
|
|
{
|
|
name: "全量替换",
|
|
description: "完全替换目标表数据"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
};
|
|
|
|
// 定义节点详细信息数据
|
|
const nodeDetails = {
|
|
"数据资产入表": {
|
|
description: "数据资产入表是将各类数据规范化并导入系统的完整流程",
|
|
steps: [
|
|
"制定数据采集计划",
|
|
"确定数据处理规则",
|
|
"设计数据存储结构",
|
|
"实施数据导入流程"
|
|
],
|
|
notes: [
|
|
"确保数据质量和完整性",
|
|
"注意数据安全和隐私保护",
|
|
"建立数据版本控制机制"
|
|
],
|
|
docs: [
|
|
"《数据资产管理规范》",
|
|
"《数据质量控制指南》",
|
|
"《数据安全管理制度》"
|
|
]
|
|
},
|
|
"数据采集": {
|
|
description: "从各种来源收集原始数据的过程",
|
|
steps: [
|
|
"识别数据源",
|
|
"建立采集通道",
|
|
"制定采集策略",
|
|
"执行数据采集"
|
|
],
|
|
notes: [
|
|
"确保数据源的可靠性",
|
|
"建立数据采集的监控机制",
|
|
"注意采集频率的控制"
|
|
],
|
|
docs: [
|
|
"《数据采集规范》",
|
|
"《数据源接入指南》"
|
|
]
|
|
},
|
|
"结构化数据": {
|
|
description: "处理来自数据库、Excel等格式化数据源的数据",
|
|
steps: [
|
|
"连接数据源",
|
|
"提取目标数据",
|
|
"验证数据格式",
|
|
"临时存储数据"
|
|
],
|
|
notes: [
|
|
"检查数据完整性",
|
|
"处理特殊字符",
|
|
"注意数据量大小"
|
|
],
|
|
docs: [
|
|
"《结构化数据处理指南》",
|
|
"《数据库连接配置手册》"
|
|
]
|
|
},
|
|
// ... 为每个节点添加详细信息
|
|
};
|
|
|
|
// 初始化D3树形图
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
// 设置SVG尺寸和边距
|
|
const margin = {top: 60, right: 120, bottom: 60, left: 120};
|
|
const width = 1200 - margin.left - margin.right;
|
|
const height = 800 - margin.top - margin.bottom;
|
|
|
|
// 创建SVG容器
|
|
const svg = d3.select('#techTree')
|
|
.append('svg')
|
|
.attr('width', '100%')
|
|
.attr('height', '100%')
|
|
.attr('viewBox', `0 0 ${width + margin.left + margin.right} ${height + margin.top + margin.bottom}`)
|
|
.append('g')
|
|
.attr('transform', `translate(${margin.left},${margin.top})`);
|
|
|
|
// 创建树形布局
|
|
const tree = d3.tree()
|
|
.size([width, height])
|
|
.separation((a, b) => (a.parent == b.parent ? 2 : 3));
|
|
|
|
// 创建层级数据
|
|
const root = d3.hierarchy(treeData);
|
|
|
|
// 计算节点位置
|
|
tree(root);
|
|
|
|
// 创建连接线 - 使用贝塞尔曲线
|
|
const link = svg.selectAll('.link')
|
|
.data(root.links())
|
|
.enter()
|
|
.append('path')
|
|
.attr('class', 'link')
|
|
.attr('d', d3.linkHorizontal()
|
|
.x(d => d.y)
|
|
.y(d => d.x));
|
|
|
|
// 创建节点组
|
|
const node = svg.selectAll('.node')
|
|
.data(root.descendants())
|
|
.enter()
|
|
.append('g')
|
|
.attr('class', d => `node${d.children ? ' node--internal' : ' node--leaf'}`)
|
|
.attr('transform', d => `translate(${d.y},${d.x})`);
|
|
|
|
// 添加节点矩形
|
|
node.append('rect')
|
|
.attr('width', 160)
|
|
.attr('height', 60)
|
|
.attr('x', -80)
|
|
.attr('y', -30)
|
|
.attr('rx', 8)
|
|
.attr('ry', 8);
|
|
|
|
// 添加节点文本
|
|
node.append('text')
|
|
.attr('dy', '0.35em')
|
|
.attr('text-anchor', 'middle')
|
|
.each(function(d) {
|
|
const text = d3.select(this);
|
|
const words = d.data.name.split('');
|
|
const lineHeight = 1.1;
|
|
const maxLength = 8;
|
|
let line = [];
|
|
let tspans = [];
|
|
|
|
words.forEach((word, i) => {
|
|
line.push(word);
|
|
if (line.length === maxLength || i === words.length - 1) {
|
|
tspans.push(line.join(''));
|
|
line = [];
|
|
}
|
|
});
|
|
|
|
tspans.forEach((tspan, i) => {
|
|
text.append('tspan')
|
|
.attr('x', 0)
|
|
.attr('dy', i === 0 ? -0.5 * (tspans.length - 1) * lineHeight + 'em' : lineHeight + 'em')
|
|
.text(tspan);
|
|
});
|
|
});
|
|
|
|
// 获取详情面板元素
|
|
const detailTitle = document.getElementById('detailTitle');
|
|
const detailDescription = document.getElementById('detailDescription');
|
|
const detailSteps = document.getElementById('detailSteps');
|
|
const detailNotes = document.getElementById('detailNotes');
|
|
const detailDocs = document.getElementById('detailDocs');
|
|
|
|
// 修改节点点击事件
|
|
node.on('click', (event, d) => {
|
|
const details = nodeDetails[d.data.name] || {
|
|
description: d.data.description || "暂无详细描述",
|
|
steps: [],
|
|
notes: [],
|
|
docs: []
|
|
};
|
|
|
|
// 更新详情面板内容
|
|
detailTitle.textContent = d.data.name;
|
|
detailDescription.textContent = details.description;
|
|
|
|
// 更新步骤列表
|
|
detailSteps.innerHTML = details.steps.map(step => `<li>${step}</li>`).join('');
|
|
|
|
// 更新注意事项
|
|
detailNotes.innerHTML = details.notes.map(note => `<li>${note}</li>`).join('');
|
|
|
|
// 更新相关文档
|
|
detailDocs.innerHTML = details.docs.map(doc => `<li>${doc}</li>`).join('');
|
|
|
|
// 添加active类到当前节点
|
|
svg.selectAll('.node').classed('active', false);
|
|
d3.select(event.currentTarget).classed('active', true);
|
|
});
|
|
|
|
// 添加缩放功能
|
|
const zoom = d3.zoom()
|
|
.scaleExtent([0.5, 2])
|
|
.on('zoom', (event) => {
|
|
svg.attr('transform', event.transform);
|
|
});
|
|
|
|
// 初始化缩放
|
|
d3.select('#techTree svg')
|
|
.call(zoom)
|
|
.call(zoom.transform, d3.zoomIdentity.translate(margin.left, margin.top));
|
|
|
|
// 绑定按钮事件
|
|
document.getElementById('zoomIn').addEventListener('click', () => {
|
|
d3.select('#techTree svg').transition()
|
|
.call(zoom.scaleBy, 1.2);
|
|
});
|
|
|
|
document.getElementById('zoomOut').addEventListener('click', () => {
|
|
d3.select('#techTree svg').transition()
|
|
.call(zoom.scaleBy, 0.8);
|
|
});
|
|
|
|
document.getElementById('resetView').addEventListener('click', () => {
|
|
d3.select('#techTree svg').transition()
|
|
.call(zoom.transform, d3.zoomIdentity.translate(margin.left, margin.top));
|
|
});
|
|
});
|