d3js基础入门

本文介绍了D3js,一个用于数据可视化的JavaScript库,特别适合创建自定义的SVG图形,如关系树。通过数据驱动DOM操作,D3js简化了复杂图形的创建,文中展示了如何使用D3js构建一个带有箭头和圆角矩形节点的树形图,包括初始化画布、绘制节点和线条以及添加交互效果。
摘要由CSDN通过智能技术生成

最近工作需要画一个关系层级比较深的树,由定制化的东西比较多,小白浅试 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 ,来画一颗有箭头的树,先上图 展示的效果是这样的:
在这里插入图片描述

初始化

定义画布 以及初始化

  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 就画完啦~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值