dagrejs / dagre

Directed graph layout for JavaScript
MIT License
4.72k stars 606 forks source link

k.toLowerCase is not a function #296

Open Mamba-working opened 4 years ago

Mamba-working commented 4 years ago
import React, { useState, useEffect, useRef, FC } from 'react'
import { x6, Graph } from '@antv/x6'
import dagre from 'dagre'

const NodeData = [
  {
    id: 'node-1',
    width: 100,
    height: 150,
    name: '推流节点'
  },  {
    id: 'node-2',
    width: 100,
    height: 150,
    name: '拉流节点'
  },  {
    id: 'node-3',
    width: 100,
    height: 150,
    name: '推流节点'
  },  {
    id: 'node-4',
    width: 100,
    height: 150,
    name: '拉流节点'
  },  {
    id: 'third-1',
    width: 100,
    height: 100,
    name: '第三方'
  },  {
    id: 'third-2',
    width: 100,
    height: 100,
    name: '第三方'
  },
  {
    id: 'tos-1',
    width: 100,
    height: 100,
    name: 'Tos',
    parent: 'region-1'
  },
  {
    id: 'source-1',
    width: 120,
    height: 120,
    name: '源站',
    parent: 'region-1'
  }, {
    id: 'tos-2',
    width: 100,
    height: 100,
    name: 'Tos',
    parent: 'region-2'
  }, {
    id: 'source-2',
    width: 120,
    height: 120,
    name: '源站',
    parent: 'region-2'
  }
]

const EdgeData = [
  {
    from: 'node-1',
    to: 'source-1'
  },  {
    from: 'source-1',
    to: 'node-2'
  },  {
    from: 'source-1',
    to: 'source-1'
  },  {
    from: 'source-1',
    to: 'third-1'
  },  {
    from: 'third-1',
    to: 'tos-1'
  }, {
    from: 'source-1',
    to: 'tos-1'
  },  {
    from: 'node-3',
    to: 'source-2'
  }, {
    from: 'source-2',
    to: 'node-4'
  },  {
    from: 'source-2',
    to: 'source-2'
  },  {
    from: 'source-2',
    to: 'source-1'
  },  {
    from: 'source-1',
    to: 'source-2'
  },  {
    from: 'source-2',
    to: 'tos-2'
  },  {
    from: 'source-2',
    to: 'third-2'
  }

]

const X6Component: FC = () => {
  const editor = useRef<Graph>();
  const container = useRef<HTMLDivElement>();
  const gagre = useRef<dagre.graphlib.Graph>();

  useEffect(() => {
    console.log(container.current)
    editor.current = x6.render({
      container: container.current
    });
    const gagreInstance = gagre.current = new dagre.graphlib.Graph().setGraph({}).setDefaultEdgeLabel(() => 'no label');
    NodeData.forEach(item => {
      gagreInstance.setNode(item.id, { label: item.name, width: item.width, height: item.height })
    })
    EdgeData.forEach(item => {
      gagreInstance.setEdge(item.from, item.to)
    })
    dagre.layout(gagreInstance);
    console.log(gagreInstance);
  }, [])

  return <div ref={container} />
}

export default X6Component

Hello, here is my code.But it cant work, but i dont know why.

It is code sandbox to reproduce it. It is a bug or what?🤣

Mamba-working commented 4 years ago

https://codesandbox.io/s/hardcore-meninsky-2sppr?file=/src/App.js

Mamba-working commented 4 years ago

i want to mock data for this picture. image

j6k4m8 commented 4 years ago

A quick search of the repo shows that your error message is coming from here: https://github.com/dagrejs/dagre/blob/5532d13fc608cff7dda54096ccc4efad4d57581c/lib/layout.js#L389

Have you tried putting a print/log statement there to see what value it's failing on?

sklinov commented 4 years ago

I'm having pretty much the same set up (just without X6 lib) and ran into the same issue. k.toLowerCase is not a function that comes from dagre/lib/layout.js

function canonicalize(attrs) {
  var newAttrs = {};
  _.forEach(attrs, function(v, k) {
    newAttrs[k.toLowerCase()] = v;
  });
  return newAttrs;
}

Can't figure out what attributes are missing or having a wrong type (not a string).

UPD: A little debugging shows that it has to do with the edges of graph (remove the edges and the error goes away).

mattmazzola commented 3 years ago

I also ran into this issue. Luckily I had one graph that worked and another that hit this so I was able to compare and see what was different. It seems it has to do with the default edge label. For some reason passing an empty string or constant string does not work, but an empty object does 😕

Try changing: g.setDefaultEdgeLabel(() => 'no label'); to: g.setDefaultEdgeLabel(() => ({}));

I would have to do more debugging to see why this matters but for now it should unblock you. The option of not setting edges has the effect of not needing to get a default label for the edges which don't have one which is why removing edges works, but that isn't feasible since graphs need edges.

Hope it helps someone!