d3-graphviz: неправильный рендеринг, если я использую один и тот же graphviz рендерер для многократного рисования немного другого графика - PullRequest
0 голосов
/ 01 мая 2018

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

  1. Создайте index.html, включая d3, d3-graphviz и viz, которые нам нужно использовать.
  2. Использовать функцию renderDot () с определенным обратным вызовом.
  3. Снова вызовите renderDot (), чтобы нарисовать еще одну, с многострочным, жирным шрифтом
  4. Выполните рендеринг снова с renderDot (), чтобы сгенерировать тот же график, что и на шаге 2

Я должен получить в самом конце, опять же:

expected graph

Однако, последний шаг (шаг 4) приводит к неправильной схеме размещения. Узлы и ребра не будут размещены в правильных положениях:

wrong layout

Также обратите внимание, что после шага 3, если я нажму на svg, он немного сместится вверх (в одном направлении), что тоже странно. После того, как мы нажмем на него, оно будет выглядеть так:

shifted upwards after svg being clicked

Вот исходный код:

index.html:

<!-- language: lang-html -->

<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src=https://d3js.org/d3.v5.min.js></script>
<script src=https://unpkg.com/viz.js@1.8.0/viz.js></script>
<script src=https://unpkg.com/d3-graphviz@1.5.0/build/d3-graphviz.min.js></script>

<!-- Main Graph -->
<div id="graph" style="text-align: center;" height=3200px width=3200px></div>

</body>

render.js:

<!-- language: typescript -->

// please run below code step by step

// create renderer
x = d3.select('#graph').graphviz()

// 1st rendering
x.renderDot(`
digraph {
    node [style="filled"]
    0 [id="0" label="honda::models"]
    1 [id="1" label="hidden"]
    2 [id="2" label="hidden"]
    0 -> 1 [id="0->1" label=""]
    0 -> 2 [id="0->2" label=""]
}
`, function() {
    d3.selectAll('text')._groups[0].forEach(function(e) {
        if (ans=/(.+?\: ).+/.exec(e.innerHTML)) {
            e.innerHTML = ans[0].replace(ans[1],
                "<tspan font-weight=bold>" + ans[1] + "</tspan>");
        }
    })
});

// 2nd rendering (bold and multi-line text label)
x.renderDot(`
digraph {
    node [style="filled"]
    0 [id="0" label="honda::models"]
    1 [id="1" label="name: fit\\linventory id: 007"]
    2 [id="2" label="hidden"]
    0 -> 1 [id="0->1" label=""]
    0 -> 2 [id="0->2" label=""]
}
`, function() {
    d3.selectAll('text')._groups[0].forEach(function(e) {
        if (ans=/(.+?\: ).+/.exec(e.innerHTML)) {
            e.innerHTML = ans[0].replace(ans[1],
                "<tspan font-weight=bold>" + ans[1] + "</tspan>");
        }
    })
});

// 3rd rendering
x.renderDot(`
digraph {
    node [style="filled"]
    0 [id="0" label="honda::models"]
    1 [id="1" label="hidden"]
    2 [id="2" label="hidden"]
    0 -> 1 [id="0->1" label=""]
    0 -> 2 [id="0->2" label=""]
}
`, function() {
    d3.selectAll('text')._groups[0].forEach(function(e) {
        if (ans=/(.+?\: ).+/.exec(e.innerHTML)) {
            e.innerHTML = ans[0].replace(ans[1],
                "<tspan font-weight=bold>" + ans[1] + "</tspan>");
        }
    })
});

Вы можете скопировать его, создав index.html, а затем пошагово запустив код в javascript.

Примечание: я оставил там функцию обратного вызова, которая обновляет шрифт, если в каждой строке он видит шаблоны "text: xxx". Не имеет значения в «скрытом» корпусе.

Спасибо!

1 Ответ

0 голосов
/ 25 мая 2018
  1. Вам необходимо сделать последующие визуализации в обратных вызовах.
  2. Манипулирование DOM, которое вы делаете, чтобы получить смелые шрифты, все портит. Вместо этого сделайте это с чистыми настройками атрибутов.

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

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

<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src=https://d3js.org/d3.v5.min.js></script>
<script src=https://unpkg.com/viz.js@1.8.0/viz.js></script>
<script src=https://unpkg.com/d3-graphviz@1.5.0/build/d3-graphviz.min.js></script>

<!-- Main Graph -->
<div id="graph" style="text-align: center;" height=3200px width=3200px></div>

<script>
  // create renderer
x = d3.select('#graph').graphviz()
  .transition(function () {return d3.transition().duration(2000)})
// replace the font-weight settings below with this if you want a bold font already from the start
//  .on("transitionStart", function() {d3.selectAll('text').attr("font-weight", "bold");});

  // 1st rendering
x.renderDot(`
digraph {
    node [style="filled"]
    0 [id="0" label="honda::models"]
    1 [id="1" label="hidden"]
    2 [id="2" label="hidden"]
    0 -> 1 [id="0->1" label=""]
    0 -> 2 [id="0->2" label=""]
}
`, function() {
    d3.selectAll('text').attr("font-weight", "bold");

    // 2nd rendering (bold and multi-line text label)
    x.renderDot(`
    digraph {
        node [style="filled"]
        0 [id="0" label="honda::models"]
        1 [id="1" label="name: fit\\linventory id: 007"]
        2 [id="2" label="hidden"]
        0 -> 1 [id="0->1" label=""]
        0 -> 2 [id="0->2" label=""]
    }
    `, function() {
        d3.selectAll('text').attr("font-weight", "bold");
        // 3rd rendering
        x.renderDot(`
        digraph {
            node [style="filled"]
            0 [id="0" label="honda::models"]
            1 [id="1" label="hidden"]
            2 [id="2" label="hidden"]
            0 -> 1 [id="0->1" label=""]
            0 -> 2 [id="0->2" label=""]
        }
        `, function() {
            d3.selectAll('text').attr("font-weight", "bold");

        });
    });
});

</script>

</body>
...