Implement D3 multiple brushes using Vue3 composition API

185 Views Asked by At

I want to implement multi-brushing functionality using D3 in a Vue3 application. Minimal examples using vanilla JS and D3 are available here and here.

Brushing functionality is correctly implemented by creating a computed variables (newBrush) and calling it in the onMounted() lifecycle hook. A minimal example is available here:

https://stackblitz.com/github/ajmoralesa/multiBrushD3Vue?embed=1

The template contains:

<template>
  <div>
    <svg :height="height" :width="width">
      <g>
        <rect :width="width" :height="height" class="rect"></rect>
        <g ref="gBrushes"></g>
      </g>
    </svg>
  </div>
</template>

And the script:

<script setup>
import { computed } from "@vue/reactivity";
import { onMounted, reactive, ref } from "vue";
import * as d3 from "d3";

const margin = reactive({
  top: 10,
  right: 10,
  bottom: 10,
  left: 10,
});
const width = 960 - margin.left - margin.right;
const height = 500 - margin.top - margin.bottom;

const gBrushes = ref();

// Keep the actual d3-brush functions and their IDs in a list:
const brushes = ref([]);

onMounted(() => {
  d3.select(gBrushes.value).call(newBrush.value);
});

const newBrush = computed(() => {
  var brush = d3.brush().on("end", brushend);

  function brushend() {
    brushes.value.push({ id: brushes.value.length, brush: brush });
    // // Figure out if our latest brush has a selection
    // var lastBrushID = brushes.value[brushes.value.length - 1].id;
    // var lastBrush = document.getElementById("brush-" + lastBrushID);
    // console.log("lastBrush:", lastBrush);

    // var selection = d3.brushSelection(lastBrush);

    // // If it does, that means we need another one
    // if (selection && selection[0] !== selection[1]) {
    //   newBrush();
    // }

    // Always draw brushes
    drawBrushes();
  }

  return brush;
});

function drawBrushes() {
  console.log("hey there!");

  var brushSelection = d3
    .select(gBrushes.value)
    .selectAll(".brush")
    .data(brushes.value, function (d) {
      return d.id;
    });

  // Set up new brushes
  brushSelection
    .enter()
    .insert("g", ".brush")
    .attr("class", "brush")
    .attr("id", function (brush) {
      return "brush-" + brush.id;
    })
    .each(function (brushObject) {
      //call the brush
      d3.select(this).call(d3.brush(brushObject));
    });


  brushSelection.each(function (brushObject) {
    d3.select(this)
      .attr("class", "brush")
      .selectAll(".overlay")
      .style("pointer-events", function () {
        var brush = brushObject.brush;
        if (
          brushObject.id === brushes.value.length - 1 &&
          brush !== undefined
        ) {
          return "all";
        } else {
          return "none";
        }
      });
  });

  brushSelection.exit().remove();
}
</script>

What is wrong in the drawBrushes() function ?

Code: https://stackblitz.com/github/ajmoralesa/multiBrushD3Vue

0

There are 0 best solutions below