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

基于GoJS的响应式组织结构图布局优化技术问询

GoJS响应式组织结构图优化方案

针对你提出的三个优化需求,以下是具体实现方案:


1. 员工节点文本横竖自适应显示

实现思路

  • 给员工节点(EMP1-EMP9)添加专属标识,区分层级节点与员工节点
  • 通过绑定TextBlock.angle属性,结合屏幕尺寸动态切换文本方向:大屏幕(>768px)下员工文本垂直旋转90度,小屏幕下保持水平
  • 窗口尺寸变化时,同步更新所有节点的文本方向

代码修改

第一步:更新模型数据,添加员工节点标识

myDiagram.model = new go.TreeModel([
  { key: "CEO", parent: "", text: "CEO" },
  { key: "DIRECTOR", parent: "CEO", text: "DIRECTOR" },
  { key: "MANAGER1", parent: "DIRECTOR", text: "MANAGER1" },
  { key: "MANAGER2", parent: "DIRECTOR", text: "MANAGER2" },
  { key: "MANAGER3", parent: "DIRECTOR", text: "MANAGER3" },
  { key: "EMP1", parent: "MANAGER1", text: "EMP1", isEmployee: true },
  { key: "EMP2", parent: "MANAGER1", text: "EMP2", isEmployee: true },
  { key: "EMP3", parent: "MANAGER1", text: "EMP3", isEmployee: true },
  { key: "EMP4", parent: "MANAGER2", text: "EMP4", isEmployee: true },
  { key: "EMP5", parent: "MANAGER2", text: "EMP5", isEmployee: true },
  { key: "EMP6", parent: "MANAGER2", text: "EMP6", isEmployee: true },
  { key: "EMP7", parent: "MANAGER3", text: "EMP7", isEmployee: true },
  { key: "EMP8", parent: "MANAGER3", text: "EMP8", isEmployee: true },
  { key: "EMP9", parent: "MANAGER3", text: "EMP9", isEmployee: true }
]);

第二步:修改节点模板,添加动态角度绑定

myDiagram.nodeTemplate =
  $(go.Node, "Auto",
    $(go.Shape, "Rectangle", { fill: "white" }),
    $(go.TextBlock, { margin: 4, textAlign: "center" },
      new go.Binding("text", "text"),
      // 根据节点类型和屏幕尺寸动态设置文本角度
      new go.Binding("angle", "", function(data) {
        if (!data.isEmployee) return 0;
        return window.innerWidth > 768 ? 90 : 0;
      }).ofObject()
    )
  );

第三步:更新resize事件处理函数,同步文本方向

function updateLayout() {
  const isSmallScreen = window.innerWidth <= 768;
  myDiagram.layout.direction = isSmallScreen ? 0 : 90;
  
  // 触发所有节点的绑定更新,同步文本角度
  myDiagram.nodes.each(node => node.updateTargetBindings());
  
  myDiagram.layoutDiagram(true);
}

2. 节点链接规整化优化

实现思路

  • 使用Orthogonal正交路由,让链接自动生成直角路径,保证线条笔直
  • 调整LayeredDigraphLayout的布局参数,统一层级间距与节点对齐方式,强化层级结构
  • 根据布局方向动态调整链接的连接点,确保路径逻辑清晰

代码修改

第一步:优化链接模板

myDiagram.linkTemplate =
  $(go.Link,
    { 
      routing: go.Link.Orthogonal, // 正交路由生成直角路径
      corner: 0, // 取消圆角,保持线条笔直
      fromSpot: go.Spot.Right,
      toSpot: go.Spot.Left
    },
    $(go.Shape, { stroke: "black", strokeWidth: 1 })
  );

第二步:优化布局参数

const myDiagram =
  $(go.Diagram, "myDiagramDiv",
    {
      initialContentAlignment: go.Spot.Center,
      layout: $(go.LayeredDigraphLayout, {
        direction: 90,
        layerSpacing: 80, // 层级间垂直间距
        columnSpacing: 40, // 同层级节点水平间距
        alignOption: go.LayeredDigraphLayout.AlignAll // 所有节点对齐到同一水平线
      })
    });

第三步:在resize函数中动态调整链接连接点

function updateLayout() {
  const isSmallScreen = window.innerWidth <= 768;
  myDiagram.layout.direction = isSmallScreen ? 0 : 90;
  
  // 根据布局方向切换链接的连接点
  myDiagram.linkTemplate.fromSpot = isSmallScreen ? go.Spot.Bottom : go.Spot.Right;
  myDiagram.linkTemplate.toSpot = isSmallScreen ? go.Spot.Top : go.Spot.Left;
  
  myDiagram.nodes.each(node => node.updateTargetBindings());
  myDiagram.layoutDiagram(true);
}

3. 小屏幕响应式适配

实现思路

  • 小屏幕下切换为垂直布局,让节点从上到下堆叠
  • 调整节点尺寸与布局间距,让结构更紧凑
  • 开启图表滚动功能,避免内容溢出;设置文本自动换行,保证内容完整显示

代码修改

第一步:增强节点模板的自适应能力

myDiagram.nodeTemplate =
  $(go.Node, "Auto",
    $(go.Shape, "Rectangle", { fill: "white" }),
    $(go.TextBlock, { 
      margin: 4, 
      textAlign: "center",
      wrap: go.TextBlock.WrapFit, // 文本过长时自动换行
      width: window.innerWidth > 768 ? 80 : NaN // 大屏幕固定宽度,小屏幕自适应
    },
      new go.Binding("text", "text"),
      new go.Binding("angle", "", function(data) {
        if (!data.isEmployee) return 0;
        return window.innerWidth > 768 ? 90 : 0;
      }).ofObject()
    )
  );

第二步:配置图表滚动与自适应

const myDiagram =
  $(go.Diagram, "myDiagramDiv",
    {
      initialContentAlignment: go.Spot.Center,
      layout: $(go.LayeredDigraphLayout, {
        direction: 90,
        layerSpacing: 80,
        columnSpacing: 40,
        alignOption: go.LayeredDigraphLayout.AlignAll
      }),
      allowHorizontalScroll: true, // 允许水平滚动
      allowVerticalScroll: true, // 允许垂直滚动
      autoScale: go.Diagram.UniformToFill // 自动缩放适配容器
    });

第三步:在resize函数中调整布局间距

function updateLayout() {
  const isSmallScreen = window.innerWidth <= 768;
  myDiagram.layout.direction = isSmallScreen ? 0 : 90;
  
  // 小屏幕下缩小布局间距,让结构更紧凑
  myDiagram.layout.layerSpacing = isSmallScreen ? 60 : 80;
  myDiagram.layout.columnSpacing = isSmallScreen ? 30 : 40;
  
  myDiagram.linkTemplate.fromSpot = isSmallScreen ? go.Spot.Bottom : go.Spot.Right;
  myDiagram.linkTemplate.toSpot = isSmallScreen ? go.Spot.Top : go.Spot.Left;
  
  // 动态更新节点宽度
  myDiagram.nodes.each(node => {
    node.width = isSmallScreen ? NaN : 80;
    node.updateTargetBindings();
  });
  
  myDiagram.layoutDiagram(true);
}

完整优化后代码

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hierarchical Organization Chart</title>
<script src="https://cdn.jsdelivr.net/npm/gojs@2.1.35/release/go.js"></script>
</head>
<body>

<div id="myDiagramDiv" style="width:100%; height:600px;"></div>

<script>
  const $ = go.GraphObject.make;
  
  // Create a new diagram
  const myDiagram =
    $(go.Diagram, "myDiagramDiv",
      {
        initialContentAlignment: go.Spot.Center,
        layout: $(go.LayeredDigraphLayout, {
          direction: 90,
          layerSpacing: 80,
          columnSpacing: 40,
          alignOption: go.LayeredDigraphLayout.AlignAll
        }),
        allowHorizontalScroll: true,
        allowVerticalScroll: true,
        autoScale: go.Diagram.UniformToFill
      });
    

  // Define the node template
  myDiagram.nodeTemplate =
    $(go.Node, "Auto",
      $(go.Shape, "Rectangle", { fill: "white" }),
      $(go.TextBlock, { 
        margin: 4, 
        textAlign: "center",
        wrap: go.TextBlock.WrapFit,
        width: window.innerWidth > 768 ? 80 : NaN
      },
        new go.Binding("text", "text"),
        new go.Binding("angle", "", function(data) {
          if (!data.isEmployee) return 0;
          return window.innerWidth > 768 ? 90 : 0;
        }).ofObject()
      )
    );

    
    // Define the link template
    myDiagram.linkTemplate =
      $(go.Link,    
        { 
          routing: go.Link.Orthogonal,
          corner: 0,
          fromSpot: go.Spot.Right,
          toSpot: go.Spot.Left
        },   
        $(go.Shape, { stroke: "black", strokeWidth: 1 })
      );

  // Set the model data for the chart
  myDiagram.model = new go.TreeModel([
    { key: "CEO", parent: "", text: "CEO" },
    { key: "DIRECTOR", parent: "CEO", text: "DIRECTOR" },
    { key: "MANAGER1", parent: "DIRECTOR", text: "MANAGER1" },
    { key: "MANAGER2", parent: "DIRECTOR", text: "MANAGER2" },
    { key: "MANAGER3", parent: "DIRECTOR", text: "MANAGER3" },
    { key: "EMP1", parent: "MANAGER1", text: "EMP1", isEmployee: true },
    { key: "EMP2", parent: "MANAGER1", text: "EMP2", isEmployee: true },
    { key: "EMP3", parent: "MANAGER1", text: "EMP3", isEmployee: true },
    { key: "EMP4", parent: "MANAGER2", text: "EMP4", isEmployee: true },
    { key: "EMP5", parent: "MANAGER2", text: "EMP5", isEmployee: true },
    { key: "EMP6", parent: "MANAGER2", text: "EMP6", isEmployee: true },
    { key: "EMP7", parent: "MANAGER3", text: "EMP7", isEmployee: true },
    { key: "EMP8", parent: "MANAGER3", text: "EMP8", isEmployee: true },
    { key: "EMP9", parent: "MANAGER3", text: "EMP9", isEmployee: true }
  ]);

  // Update layout direction based on screen size
  function updateLayout() {
    const isSmallScreen = window.innerWidth <= 768;
    myDiagram.layout.direction = isSmallScreen ? 0 : 90;
    
    // Adjust layout spacing
    myDiagram.layout.layerSpacing = isSmallScreen ? 60 : 80;
    myDiagram.layout.columnSpacing = isSmallScreen ? 30 : 40;
    
    // Adjust link spots
    myDiagram.linkTemplate.fromSpot = isSmallScreen ? go.Spot.Bottom : go.Spot.Right;
    myDiagram.linkTemplate.toSpot = isSmallScreen ? go.Spot.Top : go.Spot.Left;
    
    // Update node width and text angle
    myDiagram.nodes.each(node => {
      node.width = isSmallScreen ? NaN : 80;
      node.updateTargetBindings();
    });
    
    myDiagram.layoutDiagram(true);
  }

  // Call the function initially and on window resize
  updateLayout();
  window.addEventListener('resize', updateLayout);
</script>
</body>
</html>

内容的提问来源于stack exchange,提问作者sps

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 23:47:01