Размещение круга над искровой линией, когда пользователь меняет порядок данных

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

Это код: PLUNKER.

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

(1) Эти две строки кода определяют домен и диапазон для искровых линий. Мне кажется, что они не должны меняться при изменении порядка упорядочивания данных.

// domain and range for sparkline lines
var xSpark = d3.scaleLinear().domain([0, numYears-1]).range([0, sparkLength]); 
var ySpark = d3.scaleLinear().domain([minYvalue, maxYvalue]).range([itemSize-2, 2]);

(2) Этот фрагмент кода выбирает элемент #data-svg-i (где i - линия искровой линии), он добавляет круг, который позиционирует его в cx, cy который зависит от xSpark и ySpark. Если значение, указанное в пункте 1, истинно (т. xSpark Что xSpark и ySpark являются "фиксированными" значениями), то даже этот кусок кода не нужно изменять при изменении порядка данных.

var cells = svg.selectAll('.cell')
    .data(data)
    .enter()
    .append('g')
    .append('rect')
    .on('mouseover', function(d, i) { // on mouseover rect
        // get row, column and value of this rect
        var idr = d3.select(this).attr('data-r'); // row
        var idc = d3.select(this).attr('data-c'); // column
        var value = d3.select(this).attr('data-value');
        // highlight this rect
        d3.select(this).style('stroke', 'red');
        // add red dot to sparkline
        d3.select('#data-svg-' + idr)
            .append('circle')
            .attr('r', 3) // radius
            .style('stroke', 'red')
            .style('fill', 'red')
            .attr('cx', xSpark(idc))
            .attr('cy', ySpark(value));
    })

(3) Этот фрагмент кода также не нужно изменять при изменении порядка данных.

line = d3.line()
    .x(function(d, i) { 
        return xSpark(i); 
    })
    .y(function(d) { 
        return ySpark(d); 
    })
    .defined(function(d) { // for missing (0) data
        return d !== 0;
    });

(4) data должны обновляться, но это не так. Перед сортировкой data содержат данные в правильном порядке, в котором они отображаются, после упорядочения data не изменяются, но это должно быть, нет?

pos Я не думаю, что он должен быть изменен, а не cx и cy потому что они зависят от xSpark/ySpark и pos.

var sparkSvg = d3.select('#sparkline')
    .append('svg')
    .on('mousemove', function() { // on mousemove svg sparkline canvas
        var mouse = d3.mouse(this); // mouse position [x, y]
        var r = d3.select(this).attr('data-r'); // number of line
        var data = d3.select(this).select('path').data(); // array containing all the data values of that line

        var element = document.getElementById('data-path-' + r); // get the right path
        var pos = get_data_on_line(data, mouse);
        d3.selectAll('.data-svg').selectAll('circle').remove(); // remove old circles

        // add new circle
        d3.select('#data-svg-' + r)
            .append('circle')
            .attr('r', 3)
            .style('stroke', 'red')
            .attr('fill', 'red')
            .attr('cx', xSpark(pos[1]))
            .attr('cy', ySpark(pos[0]));
    })

Заключение

Короче говоря, я не понимаю, какая точка кода должна быть изменена и как. Кто-нибудь знает, как мне помочь?

ИЗМЕНИТЬ 1

Отметка ответа решает проблему, когда пользователь наводил курсор на прямоугольник filemap.

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

enter image description here

Я завис над искровой линией, связанной с Италией, и круг отображается не на линии, а выше. Кроме того, данные, похоже, перепутаны.

EDIT 2

Я тестирую код здесь (отметьте обновленный код). Я изменяю код, добавляя некоторые console.log(d) когда пользователь нажимает на ярлык строки и столбца:

  var rowLabels = svg.append('g')
    .attr('class', 'rowLabels')
    .selectAll('.rowLabels')
    .data(regionsName)
    .enter().append('text')
    .text(function(d) {
      return d;
    })
    .attr('x', 0)
    .attr('y', function(d, i) {
      return i * cellSize;
    })
    .attr('transform', function(d, i) {
      return 'translate(-3, 11)';
    })
    .attr('class', 'rowLabel mono')
    .attr('id', function(d) {
      return 'rowLabel_' + regionsName.indexOf(d);
    })
    .attr('label-r', function(d) {
      return regionsName.indexOf(d);
    })
    .attr('font-weight', 'normal')
    .style('text-anchor', 'end')
    .on('click', function(d, i) {
      console.log(d); // <-- ADDDED
      rowSortOrder = !rowSortOrder;
      sortByValues('r', i, rowSortOrder);
    });

  // year labels
  var colLabels = svg.append('g')
    .attr('class', 'colLabels')
    .selectAll('.colLabels')
    .data(yearsName)
    .enter().append('text')
    .text(function(d) {
      return d;
    })
    .attr('transform', function(d, i) {
      return 'translate(' + (i * cellSize) + ', 2) rotate(-65)';
    })
    .attr('class', 'colLabel mono')
    .attr('id', function(d) {
      return 'colLabel_' + yearsName.indexOf(d);
    })
    .attr('label-c', function(d) {
      return yearsName.indexOf(d);
    })
    .attr('font-weight', 'normal')
    .style('text-anchor', 'left')
    .attr('dx', '.8em')
    .attr('dy', '.5em')
    .on('click', function(d, i) {
      console.log(d); // <-- ADDDED
      colSortOrder = !colSortOrder;
      sortByValues('c', i, colSortOrder);
    });

Пример ошибки: когда пользователь нажимает на Германию, затем на 2000 год, затем на 2002 год, затем на 2005 год, затем на 2003 год и, наконец, на Италию, это результат:

enter image description here

Поскольку вы можете видеть, что искровые линии и тепловая карта неверны, поскольку у искровой линии, связанной с Italy, отсутствуют данные, которые на самом деле у нее нет.

ИЗМЕНИТЬ 3

Я создал этот gif, показывая, в чем проблема:

enter image description here

Первоначально Германия имеет две неизвестные значения (относящиеся к 2000 и 2001 годам). Соответствующая искровая линия правильная.

Когда вы нажимаете на Germany, данные сортируются в порядке убывания, а искровая линия по-прежнему правильная.

Затем нажмите на 2002 и данные будут отсортированы в порядке убывания, после чего строки будут перемещены в правильном порядке. И световые линии правильные.

Затем нажмите на 2005, данные отсортированы, а искровые линии верны.

Затем нажмите на 2003 и все будет правильно.

Наконец нажмите на Italy и график больше не верен. В Германии есть два недостающих данных, но из соответствующей искровой линии это не подсвечивается. Вместо этого две отсутствующие данные находятся на искровой линии Италии.

Ответ 1

Это новая и четкая концепция визуализации. Если я правильно понимаю, нам нужно получить полное выравнивание между прямоугольниками и искровыми линиями, накидками и всплывающими подсказками, независимо от сортировки. Для моего ответа я буду использовать plunkr, на который вы ссылаетесь сначала (а не на версию Mark). Если я правильно понял вопрос, тогда нужно решить пять вопросов:

  1. Сортировка по вертикали стирает базу данных, используемую в наведении курсора мыши

Во-первых, при сортировке вертикальных линий svg вертикально вы оцениваете новые данные - это переписывание дочерних элементов пути, поэтому после сортировки по вертикали мышь не работает при зависании над искровыми линиями (круг обнимает верхнюю часть каждого svg). См. Этот упрощенный пример, например:

var div = d3.select("body").append("div");
div.append("p").datum("hello").text(function(d) { return d; });
div.datum("new datum").select("p").text(function(d) { return d; });
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>