d3js基础入门

最近工作需要画一个关系层级比较深的树,由定制化的东西比较多,小白浅试 D3js 顺便记录一下学习过程

什么是D3js

D3js 是一个可以基于数据来操作文档的JavaScript库。可以帮助你使用 HTML、CSS、SVG 以及 Canvas来展示数据。D3 的全称是 Data-Driven Documents(数据驱动文档)

怎么理解呢?可以把 D3 当成是 svg 的 jQuery ,D3 里面提供了数据驱动DOM和一系列的 api 可供创建/ 选择 svg。

先说数据驱动,D3 里面有一些列的方法可供开发者梳理数据,再根据数据去操作 DOM,这一点与 react 的思想背道而驰D3 对DOM 的操作全是是真实 DOM react 是 VDOM;再来谈谈 SVG DOM, D3 建立了一整套数据到SVG属性的计算框架,开发者可以通过 jQuery 式操作便捷的生成一个定制化的 svg,减少了开发人员学习 SVG 成本,也不用再为生成 一条 path 而耗费精力。

如何使用

如果你是一个初学者 那么最好的方法就是手撸 demo ,来画一颗有箭头的树,先上图 展示的效果是这样的:
d3js基础入门_第1张图片

初始化

定义画布 以及初始化

  createTreeRoot (treeData) {
  	// d3.hierarchy(data[, children]) 构造有根节点的tree
    this.$root = d3.hierarchy(treeData)
    this.$root.x0 = this.nodeConfig.dx
    this.$root.y0 = this.nodeConfig.dy
    // 从当前节点开始返回其后代节点数组
    this.$root.descendants().forEach((d, i) => {
      d.id = d.data.id || getUUID()
      d.data.id = d.id
    })
    // 节点间横向和纵向的距离
    d3.tree().nodeSize([this.nodeConfig.nodeDis, this.nodeConfig.layerDis])(this.$root)
  }

画一个圆角矩形

    const nodeEnter = node.enter().append('g')
      .attr('class', this.nodeClassName)
      .attr('id', d => d.id)
      .attr('transform', d => {
        return diagonal({ x: source.x0, y: source.y0 })
      })
// 画变暖给
    nodeEnter.append('rect')
      .attr('fill', d => !d.data.isRoot ? this.nodeConfig.fill : this.nodeConfig.stroke)
      .attr('stroke', d => !d.data.isRoot ? this.nodeConfig.stroke : 'none')
      .attr('stroke-width', d => !d.data.isRoot ? 1 : 0)
      .attr('width', this.nodeConfig.width)
      .attr('height', this.nodeConfig.height)
      .attr('rx', this.nodeConfig.radius)
      .attr('ry', this.nodeConfig.radius)
      .attr('x', (this.nodeConfig.width / 2) * -1)
      .attr('y', (this.nodeConfig.height / 2) * -1)
      .attr('text-anchor', 'middle')

    const fo = nodeEnter.append('foreignObject')
      .attr('width', this.nodeConfig.width)
      .attr('height', this.nodeConfig.height)
      .attr('x', (this.nodeConfig.width / 2) * -1)
      .attr('y', (this.nodeConfig.height / 2) * -1)
      .on('mouseenter', (e, d) => {
        console.log('mouseenter', e, d)
      })
      .on('mouseleave', (e, d) => {
        console.log('mouseleave', e, d)
      })
    
    fo.append('xhtml:div')
      .style('width', `${this.nodeConfig.width}px`)
      .style('height', `${this.nodeConfig.height}px`)
      .style('font-size', `${this.nodeConfig.text.fontSize}px`)
      .style('color', d => !d.data.isRoot ? this.nodeConfig.text.fill : '#fff')
      .style('padding', '4px 6px')
      .style('text-align', 'center')
      .style('display', 'flex')
      .style('align-items', 'center')
      .style('justify-content', 'center')
      .attr('title', d => d.data.name)
      .html(d => `${d.data.name.substr(0, 20)}${d.data.name.length > 20 ? '...' : ''}`)

画线

    const linkEnter = link.enter().append('g')
      .attr('class', 'link')
    linkEnter.append('path')
      .classed('link', true)
      .attr('id', d => `${d.source.id}-${d.target.id}`)
      .attr('stroke', this.linkConfig.stroke)
      .attr('stroke-width', this.linkConfig.strokeWidth)
      .attr('fill', 'none')
      .attr('d', d => {
    const o = { x: source.x0, y: source.y0 }
        return diagonal({ source: o, target: o })
      })

画箭头

linkEnter.append('path')
        .classed('arrow', true)
        .attr('fill', this.linkConfig.arrow.fill)
        .attr('stroke-width', 0)
        .attr('d', d => {
        const o = { x: source.x0, y: source.y0 }
        return arrowDiagonal({ source: o, target: o }, this.linkConfig.arrow.size)
      })

致次一个 tree 就画完啦~

你可能感兴趣的:(javascript,前端,react.js)