D3.js + Canvas отрисовка организационной схемы

Canvas d3.js

Использовать рендеринг svg по умолчанию D3.js

Древовидная карта D3 по умолчанию использует svg, например, этот пример от автора D3:

Исходно.OCExam.org/MBO stock/43…

Есть плюсы и минусы использования svg:

  • Преимущество в том, что удобно манипулировать элементами dom и добавлять взаимодействие с пользователем.
  • Недостатком является то, что эффективность рендеринга невысока, а страница легко пропускает кадры и зависает при большом объеме данных.

В большинстве случаев, когда объем данных не особенно велик, преимущества использования svg намного перевешивают недостатки, но что, если нам действительно нужно отобразить большой объем данных?

Рендеринг с помощью D3.js + Canvas

source code

GitHub.com/SST дом/или…

demo page

SST house.GitHub.IO/organ i Разное...

demo gif

Приведенная выше демонстрация реализована с использованием D3.js + Canvas.Когда количество слоев организации превышает 300, будут очевидные лаги, которые могут соответствовать данным большинства организационных диаграмм.

идеи

  1. Трое используют D3.js в虚拟Domхорошее изображение
  2. Используйте API рисования холста, чтобы虚拟DomДанные (координаты и путь линии) и т. д. рисуются на холсте.
  3. использоватьUnique-colorСпособ реализовать взаимодействие пользователя с Canvas
  4. Рисуя скрытый холст с теми же данными, что и предыдущий холст, и присваивая каждому узлу, который хочет получать взаимодействие с пользователем, уникальный цвет.
  5. Прослушивая событие щелчка Canvas, получите значение цвета щелкнутого пикселя, чтобы определить щелкнутый узел.
  6. В этой статье есть подробное введение в эту идею:medium.com/@greener о разрушительной силе/…

1. Использование D3.js Три в虚拟Domхорошее изображение

Сначала вызовите виртуальный дом, который использует D3 для создания дерева:

this.data = this.d3.hierarchy(data)
this.treeGenerator = this.d3.tree()
  .nodeSize([this.nodeWidth, this.nodeHeight])
let nodes = this.treeData.descendants()
let links = this.treeData.links()

переменная вышеnodesа такжеlinksТеперь включает в себя каждую из структурных диаграмм组织节点а также连接线Координировать информацию.

2. Используйте API рисования холста, чтобы虚拟DomДанные (координаты и путь линии) и т. д. рисуются на холсте.

В drawShowCanvas используйте d3.select, чтобы получить узел виртуального дома, а затем используйте функцию рисования Canvas для рисования. Здесь используются некоторые инструменты и методы Util. Конкретную реализацию см. в исходном коде.

  drawShowCanvas () {
    this.context.clearRect(-50000, -10000, 100000, 100000)

    let self = this
    // draw links
    this.virtualContainerNode.selectAll('.link')
      .each(function () {
        let node = self.d3.select(this)
        let linkPath = self.d3.linkVertical()
          .x(function (d) {
            return d.x
          })
          .y(function (d) {
            return d.y
          })
          .source(function () {
            return {x: node.attr('sourceX'), y: node.attr('sourceY')}
          })
          .target(function () {
            return {x: node.attr('targetX'), y: node.attr('targetY')}
          })
        let path = new Path2D(linkPath())
        self.context.stroke(path)
      })

    this.virtualContainerNode.selectAll('.orgUnit')
      .each(function () {
        let node = self.d3.select(this)
        let treeNode = node.data()[0]
        let data = treeNode.data
        self.context.fillStyle = '#3ca0ff'
        let indexX = Number(node.attr('x')) - self.unitWidth / 2
        let indexY = Number(node.attr('y')) - self.unitHeight / 2

        // draw unit outline rect (if you want to modify this line ===>   please modify the same line in `drawHiddenCanvas`)
        Util.roundRect(self.context, indexX, indexY, self.unitWidth, self.unitHeight, 4, true, false)

        Util.text(self.context, data.name, indexX + self.unitPadding, indexY + self.unitPadding, '20px', '#ffffff')
        // Util.text(self.context, data.title, indexX + self.unitPadding, indexY + self.unitPadding + 30, '20px', '#000000')
        let maxWidth = self.unitWidth - 2 * self.unitPadding
        Util.wrapText(self.context, data.title, indexX + self.unitPadding, indexY + self.unitPadding + 24, maxWidth, 20)
      })
  }

3. ИспользуйтеUnique-colorСпособ реализовать взаимодействие пользователя с Canvas

Как вы можете видеть на рисунке ниже, на самом деле есть два Canvas, из которых Canvas ниже — это то же самое, что и данные, нарисованные Cavans выше, за исключением того, что цвет узлов отличается.

  drawCanvas () {
    this.drawShowCanvas()
    this.drawHiddenCanvas()
  }

unique color.png

Прослушайте событие щелчка пользователя на приведенном выше холсте и получите узел, щелкнутый пользователем на следующем изображении, через координаты пикселя (Примечание: пара ключ-значение цвета и узла создается, когда следующий холст рисуется из .)

  setClickListener () {
    let self = this
    this.canvasNode.node().addEventListener('click', function (e) {
      let colorStr = Util.getColorStrFromCanvas(self.hiddenContext, e.layerX, e.layerY)
      let node = self.colorNodeMap[colorStr]
      if (node) {
        // let treeNodeData = node.data()[0]
        // self.hideChildren(treeNodeData, true)
        self.toggleTreeNode(node.data()[0])
        self.update(node.data()[0])
      }
    })
  }

Вот справочный код для создания пар ключ-значение уникального цвета и узла:

  addColorKey () {
    // give each node a unique color
    let self = this
    this.virtualContainerNode.selectAll('.orgUnit')
      .each(function () {
        let node = self.d3.select(this)
        let newColor = Util.randomColor()
        while (self.colorNodeMap[newColor]) {
          newColor = Util.randomColor()
        }
        node.attr('colorKey', newColor)
        node.data()[0]['colorKey'] = newColor
        self.colorNodeMap[newColor] = node
      })
  }

разное

To draw your own nested data

please replace the data in /src/base/data-generator with your own nested data.

please add your data drawing logic in /src/components/org-chart.js #drawShowCanvas

Want to develop locally ?

source code

if you like it , welcome to star and fork :tada:

GitHub.com/SST дом/или…

# install dependencies
npm install

# serve with hot reload at localhost
npm run dev

# build for production with minification (build to ./docs folder, which can be auto servered by github page 🤓)
npm run build

Хотите узнать больше о D3.js?

вот мойD3.js,визуализация данныхадрес github, добро пожаловать на старт и форк :tada:

D3-blog

Если вы думаете, что это хорошо, вы можете нажать на ссылку ниже, чтобы обратить внимание :)

домашняя страница гитхаба

Знай колонку

Наггетс

Добро пожаловать, чтобы обратить внимание на мой общедоступный номер: