四、d3中filter的使用

609 阅读1分钟

作用

用于过滤选择集(而非过滤数据),然后就可以对过滤之后的选择集进行相关操作了。

其他说明

  • 如果通过d3在vue中动态创建dom元素,然后添加class,如果启用了scope,那么这个class默认情况下不会生效,要使其生效又要保持scope的话,必须使用::v-deep进行穿透
  • 如果数据,选择集都没发生改变,d3并不会进行dom相关操作,这一定程度上也能让d3保持更好的性能(验证方式:对同一个按钮不停点击,观察html 的dom元素变化,你会发现html的dom节点并不会每次点击都会发生变化,只有条件改变,导致选择集变化时,dom节点才会改变)

效果演示

show-05.gif

代码

<!--
TODO: 编写组件说明
@author pan
@date 2022-04-29
-->
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
import { select, selectAll } from 'd3-selection'

const myContainerRef = ref<HTMLDivElement>()
const dataArr = [
  { expense: 10, category: 'Retail' },
  { expense: 15, category: 'Gas' },
  { expense: 30, category: 'Retail' },
  { expense: 50, category: 'Dining' },
  { expense: 80, category: 'Gas' },
  { expense: 65, category: 'Retail' },
  { expense: 55, category: 'Gas' },
  { expense: 30, category: 'Dining' },
  { expense: 20, category: 'Retail' },
  { expense: 10, category: 'Dining' },
  { expense: 8, category: 'Gas' },
]

function render(data: any[], category?: string) {
  const containerDom = myContainerRef.value as HTMLDivElement
  select(containerDom)
    .selectAll('div.h-bar') // <-B
    .data(data)
    .enter()
    .append('div')
    .attr('class', 'h-bar')
    .append('span')

  select(containerDom)
    .selectAll('div.h-bar') // <-C
    .data(data)
    .exit()
    .remove()

  select(containerDom)
    .selectAll('div.h-bar') // <-D
    .data(data)
    .attr('class', 'h-bar')
    .style('width', function (d: any) {
      return d.expense * 5 + 'px'
    })
    .select('span')
    .text(function (d: any) {
      return d.category
    })

  select(containerDom)
    .selectAll('div.h-bar')
    .filter(function (d: any, i) {
      // <-E
      console.log('category', category, d)
      return d.category == category
    })
    .classed('selected', true)
}

onMounted(() => {
  render(dataArr)
})

function doFilter(category?: string) {
  render(dataArr, category)
}
</script>

<template>
  <div class="myDiv">
    <h3>表格</h3>
    <button @click="doFilter('Retail')">Retail</button>
    <button @click="doFilter('Gas')">Gas</button>
    <button @click="doFilter('Dining')">Dining</button>
    <button @click="doFilter()">Clear</button>

    <div ref="myContainerRef"></div>
  </div>
</template>

<style lang="scss" scoped>
.myDiv {
  margin-left: 30px;
  ::v-deep(.h-bar) {
    background-color: #42b8dd;
    margin-bottom: 10px;
  }
  ::v-deep(.selected) {
    background-color: pink;
  }
}
</style>