стрелки и текст после клика и наведения

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

Конечная цель примерно такая:

введите здесь описание изображения

Вот моя отправная точка, вдохновленная некоторыми базовыми уроками:

index.html

<!DOCTYPE html>
<html>
  <head>
        <script src="https://d3js.org/d3.v4.min.js"></script>
  </head>
  <body>
        <script src="script.js"></script>
  </body>
</html>

script.js

var s = 50;
var w = 200;
var h = 100;

var jsonBoxes = [
  {"name": "Box A", "x_axis": s, "y_axis": s, "width": w, "content": "content of Box A", "depends" : "Box C"},
  {"name": "Box B", "x_axis": w + 2*s, "y_axis": s, "width": w, "content": "content of Box B", "depends" : "Box D"},
  {"name": "Box C", "x_axis": 2*(w + s) + s, "y_axis": s, "width": w, "content": "content of Box C", "depends" : "Box D" },
  {"name": "Box D", "x_axis": s, "y_axis":  2*s +h, "width": w, "content" : "content of Box D" , "depends": "Box F"},
  {"name": "Box E", "x_axis": w + 2*s, "y_axis": 2*s+h, "width": w, "content": "content of Box E", "depends" : "Box F" },
  {"name": "Box F", "x_axis": 2*(w + s) + s, "y_axis": 2*s+h, "width": w, "content": "content of Box F", "depends" : "Box A" }];

var svgContainer = d3.select("body").append("svg")
                                    .attr("width", 800)
                                    .attr("height", 300);

var rectangles = svgContainer.selectAll("rect")
                          .data(jsonBoxes)
                          .enter()
                          .append("rect");

var rectanglesAttributes = rectangles
                       .attr("x", function (d) { return d.x_axis; })
                       .attr("y", function (d) { return d.y_axis; })
                       .attr("width", function (d) { return d.width; })
                       .attr("height", 100)
                       .style("fill", function(d) { return "Cornsilk"; });

var p = d3.select("body").selectAll("p")
  .data(jsonBoxes)
  .enter()
  .append("p")
  .text(function(d) { return d.name + ": " + d.content; });

Может ли кто-нибудь проиллюстрировать (/ указать мне) общую процедуру работы с наведением или щелчком и генерировать контент (стрелки, текст) на основе этого?

PS: мне вполне удобно использовать R для предварительной обработки данных в более подходящем формате. Я использовал yaml в качестве входного формата, и мне кажется, достаточно легко создавать из него json по мере необходимости. Отображение и интерактивность d3 — это то, где я полный новичок.


person baptiste    schedule 04.08.2017    source источник


Ответы (1)


Во-первых: на <svg> у вас есть <text> вместо <p>, и, к сожалению, он не свернется. Чтобы перенести текст, ознакомьтесь с блоком Майка Бостока.

Общая функциональность по клику имеет следующую форму:

selection.on('click', function (data, index) {
    stuff();
})

И зависание использует mouseover и mouseout вместо click. Для субъекта кажется, что click было бы мудрым выбором, чтобы показать стрелки и mouseover для «другого текста». В вашем случае это может выглядеть примерно так:

rectangles.on('click', function (d, i) { //1
    d3.select('svg').append('path').attr('d', pathString); //2
    d3.selectAll('rect').filter(function (k, j) {
        return k.name == d.depends; //3
    }).each(function () {
        d3.select(this).on('click')(); //4
    });
}).on('mouseover', function (d, i) { //5
    d3.select('text#moreinfo').text(d.extraInfo);
});

Стрелки должны состоять из path элементов, и у них не будет головок, если вы не добавите polygon элементов к каждой голове.

  1. Прикрепите событие клика к каждому прямоугольнику.
  2. Добавьте к элементу svg элемент path (это строка).
  3. Найдите обязательный курс rect по его названию.
  4. Вызовите событие щелчка для каждого из этих (или единичных) необходимых прямоугольников. Обратите внимание, что поскольку каждое событие щелчка настраивается таким образом, это на самом деле рекурсивный вызов, который рисует стрелки для каждого необходимого условия в цепочке.
  5. Прикрепите обработчик наведения мыши, который изменит текст элемента «текст в другом месте» text, при условии, что вы сделали это ранее.

Чтобы сделать стрелки крутыми и изогнутыми, как на изображении, вам нужно рассчитать контрольные точки пути. Вот отличный рисунок, показывающий, как пути с Кубические кривые Безье работают. Вы должны быть в состоянии рассчитать контрольные точки с некоторой базовой геометрией.

Я рекомендую сначала хорошо ознакомиться с svg.

person M. Davis    schedule 05.08.2017
comment
Спасибо. Я видел блок обтекания текстом, но это довольно сложный пример, поскольку он является частью гистограммы. Я надеюсь найти что-то более простое с div или чем-то еще ниже по странице (может быть, отдельно от svg). Что касается стрелок и кривых Безье, я бы подумал, что d3 может сделать для меня красивые пути, основываясь на примерах, которые я видел (складные деревья и т. д.). При этом, поскольку мой макет статичен, я мог бы просто сам нарисовать стрелки в inkscape, и d3 менял бы их цвет только при нажатии/наведении курсора. - person baptiste; 06.08.2017
comment
Это кажется классной идеей, и я определенно попытаюсь сделать это динамически, если вы готовы. Честно говоря, я не очень хорошо знаком с деревьями ( и я не знаю, насколько они подходят для вашей ситуации), но вы можете сделать что-то вроде это, но сделайте прямоугольники узла и поместите text поверх него. - person M. Davis; 06.08.2017
comment
Также для идеи div вы можете использовать d3 в качестве манипулятора DOM точно так же, как jQuery, с такими операторами, как: d3.select('body').append('div').text('foo'); Это, безусловно, значительно облегчит перенос; - person M. Davis; 06.08.2017