D3.js v7 диаграмма рассеяния-фокус контекст

#javascript #d3.js

Вопрос:

Я пытаюсь создать диаграмму фокуса контекста с диаграммой рассеяния, используя самую последнюю версию D3 (версия 7). Мне также нужно решение в ванильном javascript, а не импортировать наблюдаемые библиотеки.

Этот пример делает то, что я хочу, за исключением участка области, а функции экспорта не предоставляют простой javascript.

Я пытаюсь собрать код из многих прошлых вопросов SO с диаграммами рассеяния и контекстом focus , но все они из очень старых версий и используют устаревшие функции.

Я могу отобразить данные на обеих диаграммах, изменить домен на верхней диаграмме и даже заставить верхнюю ось вести себя соответствующим образом при изменении xBrush на нижней диаграмме. Но я не могу сделать точки данных на верхней диаграмме реактивными. Они остаются неподвижными независимо от того, куда движется кисть!

Что я упускаю? Как обновить точки данных на верхней диаграмме?

Вот мой код:

 <!DOCTYPE html>
<meta charset="utf-8">

<style type="text/css">

    #zoom-map{
        width: 100%;
        height: 100px;
    }

    .tag1{
        stroke: royalblue;
    }
    .tatag2{
        stroke: seagreen;
        stroke-width: 2;
    }

</style>

<body>
    <section id="zoom-map">

    </section>
    <section id="brush-map">

    </section>
</body>

<!-- Load in the d3 library -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.0.4/d3.min.js"></script>
<script>

// 2. Use the margin convention practice 
var margin = {top: 10, right: 0, bottom: 20, left: 5}

const map_width = 1000
const map_height = 100

const width = map_width - margin.left - margin.right // - (strokeWidth * 2);
const height = map_height - margin.top - margin.bottom;

// The number of minutes
var n = 20;

// 5. X scale will use the index of our data
var xZoom = d3.scaleLinear()
    .domain([0, 4]) // input
    .range([0, width]); // output

var xZoomAxis = d3.axisBottom(xZoom)


// Add the zoom-map SVG to the page
var svg_zoom = d3.select("#zoom-map").append("svg")
    .attr("width", '100%') //   margin.left   margin.right)
    .attr("height", '100%') //   margin.top   margin.bottom)
    // .attr('viewbox', `0 0 ${map_width} ${map_height}`)
    // .attr('preserveAspectRatio','xMinYMin')
    .append("g")
    .attr("transform", `translate( ${margin.left}, ${margin.top})`)

// Call the x axis in a group tag
svg_zoom.append("g")
    .attr("class", "x axis")
    .attr("transform", `translate(0,${height})`)
    .call(xZoomAxis); // Create an axis component with d3.axisBottom

var event_data = [{frame: 1, time: 1, type: 'tag1'}, {frame: 5, time: 5, type: 'tag1'}, {frame: 7, time: 7, type: 'tag2'}, {frame: 10.4, time: 10.4, type: 'tag1'}, {frame: 14, time: 14, type: 'tag1'}, {frame: 17, time: 17, type: 'tag2'}, ]

svg_zoom.selectAll('.event')
    .data(event_data)
    .enter()
    .append('rect')
    .attr('x', function(tag){return xZoom(tag.time)})
    .attr('y', 5)
    .attr('width', 1)
    .attr('height', 70)
    .attr('class', 'event')
    .attr('class', function(tag){return tag.type} )
    

// Create brush on x-axis
var xBrush = d3.scaleLinear()
    .domain([0, n]) // input
    .range([0, width]); // output

// Add the brush-map SVG to the page
var svg_brush = d3.select("#brush-map").append("svg")
    .attr("width", '100%') //   margin.left   margin.right)
    .attr("height", '100%') //   margin.top   margin.bottom)
    // .attr('viewbox', `0 0 ${map_width} ${map_height}`)
    // .attr('preserveAspectRatio','xMinYMin')
    .append("g")
    .attr("transform", `translate( ${margin.left}, ${margin.top})`)

// Call the x axis in a group tag
svg_brush.append("g")
    .attr("class", "x axis")
    .attr("transform", `translate(0,${height})`)
    .call(d3.axisBottom(xBrush)); // Create an axis component with d3.axisBottom

// Add rectangles to the brush-map
svg_brush.selectAll('.event')
    .data(event_data)
    .join('rect')
    .attr('x', function(tag){return xBrush(tag.time)})
    .attr('y', 5)
    .attr('width', 1)
    .attr('height', 70)
    .attr('class', 'event')
    .attr('class', function(tag){return tag.type} )

function brushed({selection}) {
    if (selection) {
        coords = selection.map(xBrush.invert, xBrush)
        xZoom.domain( coords)
        svg_brush.property("value", selection.map(xBrush.invert, xBrush))
        svg_brush.dispatch("input")
        
        svg_zoom.selectAll('.event')
            // .join()
            .data(event_data)
            .attr('x', (tag) => xZoom(tag.time))
            .call(xZoom)
            // .attr('x', function(event){return xZoom(event.time)})
        // svg_zoom.dispatch("input")
        svg_zoom.select(".x.axis") // change the x axis
            .call(xZoomAxis);
    }
}

const brush = d3.brushX()
    .extent([[0, 0], [width, height]])
    .on("brush", brushed)

const defaultSelection = [100,200] // this is pixels

const gb = svg_brush.append("g")
      .call(brush)
      .call(brush.move, defaultSelection);

</script>