zoukankan      html  css  js  c++  java
  • d3根据数据绘制不同的形状

       绘制力导向图的时候通常节点都是圆形,但也会遇到公司节点绘制成圆型,人绘制成方形的情况,那我们怎么依据数据绘制不同的形状。

       你可能首先会想到,这很简单啊,是公司的时候append circle,是人的时候append rect。但是append并没有提供回调也就是说我们不能这样做

    node.append((data)=>{
       return data.type === 'person'  ? 'rect' : 'circle';  
    });

      下面介绍两种方案:

     第一种,先append一个g然后根据数据设置不同的类名

    var nodeGUpdate = this.nodeG
                      .selectAll('g')
                      .data(this.nodesData, (data) => data.id);

    var nodeGEnter = nodeGUpdate.enter(); var nodeGExit = nodeGUpdate.exit(); // 更新 nodeGUpdate
    .transition() .attr(
    'class', (data) => {   return (data.hide && 'hide') || (data.nodeStatus < 0 && 'noActive') || (data.cateType === 0 && 'mainCompany') || (data.cateType === 1 && 'relativeCompany') || (data.cateType === 2 && 'relativePerson'); }) nodeGEnter.append('g')
    .attr(
    'class', (data)=> {   return data.cateType === 2 ? 'person' : 'company'; })

    然后依据类名append不同形状

    添加矩形

    this.nodeG
    .selectAll('.person')
    .append('rect')
    .attr('class', (data) => {
      return (data.hide && '.hide') || (data.cateType === 0 && 'mainCompany') || (data.cateType === 1 && 'relativeCompany') || (data.cateType === 2 && 'relativePerson');
     })
    .attr('width', 20)
    .attr('height', 20);

    添加圆形

    this.nodeG
    .selectAll('.company')
    .append('circle')
    .attr('class', (data) => {
       return (data.hide && '.hide') || (data.cateType === 0 && 'mainCompany') || (data.cateType === 1 && 'relativeCompany') || (data.cateType === 2 && 'relativePerson');
     })
    .attr('r', 20);

    最后效果

    这有点尴尬,矩形是以它自身的左上角的为基点,所以你可能还需要根据象限进行平移。

    上面这种思路是我从其它文章看来的,但出处忘了,但是由于还要将矩形的中心移到线的端点太麻烦,所以最终没有采用这种方法。

    下面来讲另外一种方法

    整体思路是统一append circle 但是当是人的时候填充圆形。就是可以想象append的这个circle相当于一个透明的画布,如果fill的值是颜色,那就是用这个颜色去填充这个圆。如果fill的是一个形状,就是用这个形状填充,由于背景是透明的,所以看起来好像append了其它形状上去。

    首先在svg中定义一个矩形,defs简单来说就是一个容器,在这个元素里面你可以定义一些元素供你重复使用,例如箭头和这里定义的矩形。

    这里有几个地方需要注意:

    矩形 x,y的值

    x,y是矩形的左上角相对于圆形的位置,设置x,y的值将矩形移至圆的中心,这样才能确保线的端点指向矩形的中心。

    计算公式是 x=y = r  - 矩形宽度 / 2

    确保矩形小于圆的内切正方形

    打个比方,如果你透过一个圆形孔看一个较小的红色正方形,你会看到一个个完整的正方形,但如果正方形过大,你可能就只能看到一个红色的圆形了。

    所以正方形宽度推导公式就是 width < 2*r / √2

    <svg width="1000" height="1000">
      <defs>
         <pattern id="person" patternUnits="objectBoundingBox" width="1" height="1">
             <rect x="10" y="10" width="20" height="20" fill="#7FBBA1" stroke="#5CA083"/>
           </pattern>
        </defs>
     </svg>

    确保圆是透明的

    通俗点讲就是用于填充矩形的圆的样式中不能在设置fill和stroke了

     然后在绘制圆形的地方引用

    nodeEnter
      .append('circle')
        .attr('class', (data) => {
           return (data.hide && '.hide') || (data.cateType === 0 && 'mainCompany') || (data.cateType === 1 && 'relativeCompany') || (data.cateType === 2 && 'shape-relativePerson');
        })
        .attr('r', 20)
        .attr('fill', (data)=>{
            return data.cateType === 2 ? 'url(#person)' : '';
         })

    下面是结果图

    当然你可以扩展,例如如果是人的话绘制一个人的图片

    <pattern id="person" patternUnits="objectBoundingBox" width="1" height="1">
      <image href={user} width="20" height="20" x="10" y="10"/>
    </pattern>

    效果如图

  • 相关阅读:
    每周必写
    每周必写
    每周必写
    感想及阅读内容
    阅读内容及感想
    每周感想和阅读内容
    每周感想及阅读内容
    每周感想及阅读内容
    分答
    每周感想及阅读内容
  • 原文地址:https://www.cnblogs.com/baize-q/p/7729847.html
Copyright © 2011-2022 走看看