Echarts-知识图谱

Echarts-知识图谱

demo地址

打开CodePen

效果

在这里插入图片描述

思路

1. 生成根节点
2. 根据子节点距离与根节点的角度关系,生成子节点坐标,进而生成子节点
3. 从子节点上按角度生成对应的子节点
4. 递归将根节点与每一层级子节点连线

核心代码

  • 定义节点配置
function getNodeConfig() {
  return {
    /** 节点间距 */
    nodeLine: 120,
    /** 节点大小 */
    nodeSize: 100,
    /** 子节点间距 */
    subNodeLine: 40,
    /** 子节点大小 */
    subNodeSize: 60
  };
}
  • 创建节点位置
function createNodePos({ index: i, len: iLen }) {
  const { nodeLine } = getNodeConfig();
  const radioDeg = (Math.PI * 2) / iLen;
  const deg = i * radioDeg + Math.PI / 4;
  const x = nodeLine * Math.cos(deg);
  const y = nodeLine * Math.sin(deg);

  const pos = { x, y };
  return pos;
}
  • 创建子节点位置
function createSubNodePos({ index: i, len: iLen }, { index: j, len: jLen }) {
  const { nodeLine, subNodeLine } = getNodeConfig();
  const radioDeg = (Math.PI * 2) / iLen;
  const deg = i * radioDeg + Math.PI / 4;
  const parentX = nodeLine * Math.cos(deg);
  const parentY = nodeLine * Math.sin(deg);

  const subRadioDeg = (Math.PI * 2) / (jLen + 1);
  const subDeg = j * subRadioDeg + (Math.PI / 2) * 3 + deg;
  const x = parentX + subNodeLine * Math.cos(subDeg);
  const y = parentY + subNodeLine * Math.sin(subDeg);

  const pos = { x, y };
  return pos;
}
  • 创建节点和链接
function initOption(root) {
  root.categoryItem = categories?.[root?.category] || {};
  const list = chartList || [];
  const graph = {
    ...createNodesLinks(list, root),
    categories
  };

  const chartOption = {
    color: categories?.map((item) => item?.color),
    legend: [
      {
        orient: 'vertical',
        left: 0,
        data: graph.categories.map(function (a) {
          return a.name;
        })
      }
    ],
    tooltip: {
      formatter: (params) => {
        return params?.data?.name;
      }
    },
    animationDuration: 1500,
    animationEasingUpdate: 'quinticInOut',
    series: [
      {
        type: 'graph',
        layout: 'none',
        force: {
          repulsion: 100
        },
        data: graph.nodes,
        links: graph.links,
        categories: graph.categories,
        roam: true,
        label: {
          show: true,
          width: 36,
          height: 36,
          overflow: 'breakAll',
          color: '#f2f2f2',
          formatter: (params) => {
            const { name = '', id } = params?.data || {};
            const len = id === rootId ? 20 : 10;
            return name?.length > len ? name?.slice(0, len) + '...' : name;
          }
        },
        lineStyle: {
          color: 'source',
          curveness: 0.3
        },
        emphasis: {
          focus: 'adjacency',
          disabled: true,
          lineStyle: {
            width: 10
          }
        }
      }
    ]
  };
  option = chartOption;
}

function createNodesLinks(list = [], root = {}) {
  const nodes = [];
  const links = [];
  const { nodeSize, subNodeSize } = getNodeConfig();

  nodes.push({
    id: rootId,
    category: 0,
    name: '根节点',
    ...root,
    symbolSize: nodeSize,
    x: 0,
    y: 0
  });

  for (let i = 0; i < list.length; i++) {
    const iIndex = String(i);
    const categoryItem = categories?.[i];
    nodes.push({
      id: iIndex,
      category: i,
      symbolSize: 1,
      label: {
        show: false
      },
      name: categoryItem?.name,
      ...createNodePos({ index: i, len: list.length })
    });
    links.push({
      source: rootId,
      target: iIndex
    });
    for (let j = 0; j < list[i].length; j++) {
      const jIndex = `${i}.${j}`;
      const jItem = _.get(list, jIndex, {});
      nodes.push({
        id: jIndex,
        category: i,
        symbolSize: subNodeSize,
        ...jItem,
        ...createSubNodePos({ index: i, len: list.length }, { index: j, len: list[i].length })
      });
      links.push({
        source: iIndex,
        target: jIndex
      });
    }
  }

  return { nodes, links };
};
  • 初始化
function init() {
  const { id, name, key } = { id: '1', name: '青霉素', key: 'drug-research' }
  const category = categories?.findIndex((item) => item?.key === key);
  const categoryItem = categories?.[category];
  initOption({
    category,
    dataId: id,
    name,
    id: rootId
  })
}

完整代码

var dom = document.getElementById('chart-container');
var myChart = echarts.init(dom, null, {
  renderer: 'canvas',
  useDirtyRect: false
});
var app = {};

var option;

const categories = [
    {
      name: '药物',
      color: 'rgba(0, 136, 184, 1)',
      key: 'drug-research',
      enumKey: 'Drug',
      fieldKey: 'drug',
      idKey: 'drug_uid',
      nameKey: 'drug_name_cn',
      nameEnKey: 'drug_name_en'
    },
    {
      name: '靶点',
      color: 'rgba(7, 214, 205, 1)',
      key: 'target-spot',
      enumKey: 'Target',
      fieldKey: 'target',
      idKey: 'target_uid',
      nameKey: 'target_name'
    },
    {
      name: '适应症',
      color: 'rgba(236, 153, 41, 1)',
      key: 'indications',
      enumKey: 'Indication',
      fieldKey: 'indication',
      idKey: 'indication_uid',
      nameKey: 'indication_name'
    },
    {
      name: '企业',
      color: 'rgba(210, 142, 200, 1)',
      key: 'company',
      enumKey: 'Entity',
      fieldKey: 'entity',
      idKey: 'entity_uid',
      nameKey: 'entity_name'
    },
    {
      name: '药物设计技术',
      color: 'rgba(255, 192, 185, 1)',
      key: 'drug-tech',
      enumKey: 'Tech',
      fieldKey: 'tech',
      idKey: 'tech_name',
      nameKey: 'tech_name'
    }
  ];

const rootId = 'root';
  
const serverMapData = {
  "drug": [
    {
      "drug_uid": "1",
      "drug_name_cn": "药物1",
      "drug_name_en": "药物en"
    },
    {
      "drug_uid": "2",
      "drug_name_cn": "药物2",
      "drug_name_en": "药物en"
    },
    {
      "drug_uid": "3",
      "drug_name_cn": "药物3",
      "drug_name_en": "药物en"
    },
    {
      "drug_uid": "4",
      "drug_name_cn": "药物4",
      "drug_name_en": "药物en"
    },
    {
      "drug_uid": "5",
      "drug_name_cn": "药物5",
      "drug_name_en": "药物en"
    },
  ],
  "target": [
    {
      "target_uid": "1",
      "target_name": "靶点1",
      "target_code": [
        "string"
      ]
    },
    {
      "target_uid": "2",
      "target_name": "靶点2",
      "target_code": [
        "string"
      ]
    },
    {
      "target_uid": "3",
      "target_name": "靶点3",
      "target_code": [
        "string"
      ]
    },
    {
      "target_uid": "4",
      "target_name": "靶点4",
      "target_code": [
        "string"
      ]
    },
    {
      "target_uid": "5",
      "target_name": "靶点5",
      "target_code": [
        "string"
      ]
    },
  ],
  "indication": [
    {
      "indication_uid": "1",
      "indication_name": "适应症1",
      "indication_code": [
        "string"
      ]
    },
    {
      "indication_uid": "2",
      "indication_name": "适应症2",
      "indication_code": [
        "string"
      ]
    },
    {
      "indication_uid": "3",
      "indication_name": "适应症3",
      "indication_code": [
        "string"
      ]
    },
    {
      "indication_uid": "4",
      "indication_name": "适应症4",
      "indication_code": [
        "string"
      ]
    },
    {
      "indication_uid": "5",
      "indication_name": "适应症5",
      "indication_code": [
        "string"
      ]
    },
  ],
  "entity": [
    {
      "entity_uid": "1",
      "entity_name": "企业1",
      "entity_code": [
        "string"
      ]
    },
    {
      "entity_uid": "2",
      "entity_name": "企业2",
      "entity_code": [
        "string"
      ]
    },
    {
      "entity_uid": "3",
      "entity_name": "企业3",
      "entity_code": [
        "string"
      ]
    },
    {
      "entity_uid": "4",
      "entity_name": "企业4",
      "entity_code": [
        "string"
      ]
    },
    {
      "entity_uid": "5",
      "entity_name": "企业5",
      "entity_code": [
        "string"
      ]
    },
  ],
  "tech": [
    {
      "tech_name": "技术1"
    },
    {
      "tech_name": "技术2"
    },
    {
      "tech_name": "技术3"
    },
    {
      "tech_name": "技术4"
    },
    {
      "tech_name": "技术5"
    },
  ]
}
  
const chartList = categories?.map((categoryItem) => {
  const dataList = serverMapData?.[categoryItem?.fieldKey] || [];
  return dataList?.map((item) => {
    return {
      ...item,
      categoryItem,
      dataId: item?.[categoryItem?.idKey],
      name: item?.[categoryItem?.nameKey] || item?.[categoryItem?.nameEnKey]
    };
  });
});

init();

function init() {
  const { id, name, key } = { id: '1', name: '青霉素', key: 'drug-research' }
  const category = categories?.findIndex((item) => item?.key === key);
  const categoryItem = categories?.[category];
  initOption({
    category,
    dataId: id,
    name,
    id: rootId
  })
}
  
function initOption(root) {
    root.categoryItem = categories?.[root?.category] || {};
    const list = chartList || [];
    const graph = {
      ...createNodesLinks(list, root),
      categories
    };

    const chartOption = {
      color: categories?.map((item) => item?.color),
      legend: [
        {
          orient: 'vertical',
          left: 0,
          data: graph.categories.map(function (a) {
            return a.name;
          })
        }
      ],
      tooltip: {
        formatter: (params) => {
          return params?.data?.name;
        }
      },
      animationDuration: 1500,
      animationEasingUpdate: 'quinticInOut',
      series: [
        {
          type: 'graph',
          layout: 'none',
          force: {
            repulsion: 100
          },
          data: graph.nodes,
          links: graph.links,
          categories: graph.categories,
          roam: true,
          label: {
            show: true,
            width: 36,
            height: 36,
            overflow: 'breakAll',
            color: '#f2f2f2',
            formatter: (params) => {
              const { name = '', id } = params?.data || {};
              const len = id === rootId ? 20 : 10;
              return name?.length > len ? name?.slice(0, len) + '...' : name;
            }
          },
          lineStyle: {
            color: 'source',
            curveness: 0.3
          },
          emphasis: {
            focus: 'adjacency',
            disabled: true,
            lineStyle: {
              width: 10
            }
          }
        }
      ]
    };
    console.log('chartOption', chartOption)
    option = chartOption;
  }

  function createNodesLinks(list = [], root = {}) {
    const nodes = [];
    const links = [];
    const { nodeSize, subNodeSize } = getNodeConfig();

    nodes.push({
      id: rootId,
      category: 0,
      name: '根节点',
      ...root,
      symbolSize: nodeSize,
      x: 0,
      y: 0
    });

    for (let i = 0; i < list.length; i++) {
      const iIndex = String(i);
      const categoryItem = categories?.[i];
      nodes.push({
        id: iIndex,
        category: i,
        symbolSize: 1,
        label: {
          show: false
        },
        name: categoryItem?.name,
        ...createNodePos({ index: i, len: list.length })
      });
      links.push({
        source: rootId,
        target: iIndex
      });
      for (let j = 0; j < list[i].length; j++) {
        const jIndex = `${i}.${j}`;
        const jItem = _.get(list, jIndex, {});
        nodes.push({
          id: jIndex,
          category: i,
          symbolSize: subNodeSize,
          ...jItem,
          ...createSubNodePos({ index: i, len: list.length }, { index: j, len: list[i].length })
        });
        links.push({
          source: iIndex,
          target: jIndex
        });
      }
    }

    return { nodes, links };
  };

  function getNodeConfig() {
    return {
      nodeLine: 120,
      nodeSize: 100,
      subNodeLine: 40,
      subNodeSize: 60
    };
  }

  function createNodePos({ index: i, len: iLen }) {
    const { nodeLine } = getNodeConfig();
    const radioDeg = (Math.PI * 2) / iLen;
    const deg = i * radioDeg + Math.PI / 4;
    const x = nodeLine * Math.cos(deg);
    const y = nodeLine * Math.sin(deg);

    const pos = { x, y };
    return pos;
  }

  function createSubNodePos({ index: i, len: iLen }, { index: j, len: jLen }) {
    const { nodeLine, subNodeLine } = getNodeConfig();
    const radioDeg = (Math.PI * 2) / iLen;
    const deg = i * radioDeg + Math.PI / 4;
    const parentX = nodeLine * Math.cos(deg);
    const parentY = nodeLine * Math.sin(deg);

    const subRadioDeg = (Math.PI * 2) / (jLen + 1);
    const subDeg = j * subRadioDeg + (Math.PI / 2) * 3 + deg;
    const x = parentX + subNodeLine * Math.cos(subDeg);
    const y = parentY + subNodeLine * Math.sin(subDeg);

    const pos = { x, y };
    return pos;
  }
  

if (option && typeof option === 'object') {
  myChart.setOption(option);
}

window.addEventListener('resize', myChart.resize);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/576119.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

目标检测——大规模商品数据集

引言 亲爱的读者们&#xff0c;您是否在寻找某个特定的数据集&#xff0c;用于研究或项目实践&#xff1f;欢迎您在评论区留言&#xff0c;或者通过公众号私信告诉我&#xff0c;您想要的数据集的类型主题。小编会竭尽全力为您寻找&#xff0c;并在找到后第一时间与您分享。 …

阿里云企业邮箱API的使用方法?调用限制?

阿里云企业邮箱API性能如何优化&#xff1f;配置邮箱API的优势&#xff1f; 阿里云企业邮箱以其稳定、高效和安全的特点&#xff0c;受到了众多企业的青睐。而阿里云企业邮箱API的开放&#xff0c;更是为企业提供了更加灵活、便捷的管理和操作方式。下面&#xff0c;我AokSend…

新标准日本语初下 课后练习作业

新版标准日本语初下 第二十五課 これは明日会議で使う資料です 第二十五課 これは明日会議で使う資料です &#xff12;&#xff14;&#xff0d;&#xff10;&#xff14;&#xff0d;&#xff12;&#xff16; 練習&#xff12;&#xff15;&#xff0d;1&#xff0d;1 例…

uniapp中vue写微信小程序的生命周期差别

根据uniapp官网里的生命周期&#xff0c;感觉不太对劲&#xff0c;就自己测试了几个&#xff0c;发现有所差别。 红字数字 为 实际测试生命周期顺序。 因为需要页面传参 后再 初始化数据&#xff0c;而onLoad(option)接收参数后&#xff0c;就已经过了create()了&#xff0c;所…

绘制等值线地图——以气压等压线为例(Python版)

绘制等值线地图——以气压等压线为例(Python版&#xff09; - 知乎 1.前期环境配置 本篇博客主要使用了basemap和netCDF4两个库&#xff0c;推荐使用conda新建虚拟环境并安装相关的包 可以参考笔者之前的博客1和博客2完成windows系统上conda的安装在conda完成安装后在anacond…

【牛客网】:链表的回文结构(提升)

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;每日一练 &#x1f337;追光的人&#xff0c;终会万丈光芒 目录 &#x1f3dd;问题描述&#xff1a; &#x1f3dd;问题分析&#xff1a; 步骤一&#xff1a;查找链表的中间节点 步骤二&am…

C++教学——从入门到精通 11.嵌套循环及数组

上次讲到了循环&#xff0c;这次来讲嵌套循环 如果一个人叫你用C来画一个10*10/2cm^2三角形会么&#xff1f; 这就要用到嵌套循环了 来看看结构&#xff1a; for(变量类型1 变量;条件1;返回值1){语句1;for(变量类型 变量2;条件2;返回值2){语句2;}语句3; } 语句1,2,3是依次…

ThingsBoard远程RPC调用设备

使用 RPC 功能 客户端 RPC 从设备发送客户端 RPC 平台处理客户端RPC 服务器端 RPC 服务器端RPC结构 发送服务器端RPC 使用 RPC 功能 ThingsBoard 允许您从服务器端应用程序向设备发送远程过程调用 (RPC)&#xff0c;反之亦然。基本上&#xff0c;此功能允许您向设备发送命…

关于discuz论坛网址优化的一些记录(伪静态)

最近网站刚上线&#xff0c;针对SEO做了些操作&#xff0c;为了方便网站网页被收录&#xff0c;特此记录下 1.开启伪静态 按照操作勾选所有项&#xff0c;然后点击查看伪静态规则 2.打开宝塔&#xff0c;找到左侧列表的网站&#xff0c;然后找到相应站点的设置。把discuz自动…

科普:嵌入式代码软件在环(SiL)测试的可靠性

关键词&#xff1a;嵌入式系统、软件在环&#xff08;SiL&#xff09;、测试、生命周期 01.简介 当前&#xff0c;嵌入式系统开发的大趋势为通过软件实现大量的硬件功能&#xff0c;这导致软件的复杂程度显著上升——代码开发成本和风险也成倍增加。复用已有系统中的软件组件…

【数据结构(邓俊辉)学习笔记】绪论05——动态规划

文章目录 0.前言1. Fibonacci数应用1.1 fib&#xff08;&#xff09;&#xff1a;递归1.1.1 问题与代码1.1.2 复杂度分析1.1.3 递归分析 1.2 fib&#xff08;&#xff09;&#xff1a;迭代 0.前言 make it work,make it right,make it fast. 让代码能够不仅正确而且足够高效地…

明日周刊-第7期

转眼间就又快到了五一假期&#xff0c;小长假有什么计划吗。封面配图是杭州高架上的月季花&#xff0c;非常好看。 文章目录 一周热点资源分享言论歌曲推荐 一周热点 鸿蒙系统持续扩大影响力&#xff1a;近期&#xff0c;华为官方宣布广东省已有超过600款应用加入鸿蒙系统&…

大模型的研究新方向:混合专家模型(MoE)

大模型的发展已经到了一个瓶颈期,包括被业内所诟病的罔顾事实而产生的“幻觉”问题、深层次的逻辑理解能力、数学推理能力等,想要解决这些问题就不得不继续增加模型的复杂度。随着不同应用场景的实际需求,大模型的参数会变得越来越大,复杂性和规模不断的增加,尤其是在多模…

C# 生成图形验证码

目录 应用场景 开发运行环境 设计 生成内容 生成图片 实现 核心代码 调用示例 小结 应用场景 我们当用户登录系统时经常会用到图形验证码技术&#xff0c;要求用户识别图片中的内容&#xff0c;并正确输入&#xff0c;方可尝试登录。类似的场景还有用户注册或者涉及…

svg图标填充渐变色及CSS鼠标悬停纯色渐变色转换

svg图标填充渐变色及CSS鼠标悬停纯色渐变色转换&#xff1a; HTML&#xff1a; <!--底部导航--> <ul class"milliaNav"> <li class"active"><a href"#"> <svg class"icon" viewBox"0 0 1024 1024&qu…

随手记:树结构翻页和定位指定数据逻辑

业务背景&#xff1a; 树形组件展示数据&#xff0c;数据包含过去数据&#xff0c;现在数据&#xff0c;未来数据&#xff0c;用户在首次进入页面时&#xff0c;展示的是当天的数据&#xff0c;如果当天没有数据&#xff0c;则显示最近一条的过去数据。数据按照时间越长数据会…

【AMBA Bus ACE 总线 5 -- Non-cached master】

文章目录 Non-cached masterNon-cached master 图 1-1 Non-cached master 意思就是,比如对于master0,它想写的时候,就直接发起transaction,它不是对自己的local cache进行操作,比如以non-shareable write 为例,master0在写的时候分别在AW,和 W channel发起命令和数据,见…

CV | 360BEV: Panoramic Semantic Mapping for Indoor Bird‘s-Eye View理解

本文主要是对于论文360BEV的解读和实现。 Paper:2023.03_360BEV: Panoramic Semantic Mapping for Indoor Birds-Eye View 360BEV&#xff1a;室内鸟瞰全景语义映射 arxiv.org/pdf/2303.11910 Code:jamycheung/360BEV: Repository of 360BEV (github.com) Demo:360BEV (jamyche…

win11 修改hosts提示无权限

win11下hosts的文件路径 C:\Windows\System32\drivers\etc>hosts修改文件后提示无权限。 我做了好几个尝试&#xff0c;都没个啥用~比如&#xff1a;右键 管理员身份运行&#xff0c;在其他版本的windows上可行&#xff0c;但是win11不行&#xff0c;我用的是微软账号登录的…

Android 组件提供的状态保存(saveInstanceState)与恢复(restoreInstanceState)

在Android的组件Activity中&#xff0c;有这样一对方法: onSaveInstanceeState 和 onRestoreInstanceState 这两对方法&#xff0c;可以让我在Activiy被异常销毁时&#xff0c;保存状态&#xff1b;以及在Activity重建时&#xff0c;恢复状态。 比如&#xff1a;当我们在输入…