D3.JS Пузырьковая диаграмма — сброс диаграммы при уменьшении размера круга

#jquery #d3.js

#jquery #d3.js

Вопрос:

У меня возникли некоторые проблемы с пузырьковой диаграммой, используя D3.JS (https://d3js.org /).

Я почти уверен, что я просто не понимаю библиотеку. Любой hep был бы оценен

Когда я создаю пузырьковую диаграмму и добавляю событие onclick с помощью jQuery к кругу, чтобы уменьшить его радиус, диаграмма не обновляется. Это оставляет круги с тем же заполнением, как если бы круг полного размера все еще был на месте.

Мой вопрос в том, как мне сбросить или повторно сгенерировать диаграмму, чтобы использовался новый размер кругов и не оставалось неприглядных пробелов?

Вот мой код:

 <!DOCTYPE html>
<html>
<head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <meta name="robots" content="noindex, nofollow">
  <meta name="googlebot" content="noindex, nofollow">
      <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
      <script type="text/javascript" src="https://d3js.org/d3.v4.min.js"></script>
      <script type="text/javascript" src="//rawgit.com/ngryman/jquery.finger/v0.1.2/dist/jquery.finger.js"></script>
  <title></title>
<script type='text/javascript'>//<![CDATA[
$(document).ready(function () {
        var width = 700,
        height = 700,
        padding = 12,
        clusterPadding = 4,
        maxRadius = 36;

        var n = 17,
            m = 1;

        var color = d3.scale.category10().domain(d3.range(m));
        var clusters = new Array(m);

        var nodes = d3.range(n).map(function () {
            var i = m,
                r = 36,
                d = {
                    cluster: i,
                    radius: r,
                    name: "Label",
                    x: Math.cos(i / m * 2 * Math.PI) * 200   width / 2   Math.random(),
                    y: Math.sin(i / m * 2 * Math.PI) * 200   height / 2   Math.random()
                };

            if (!clusters[i] || (r > clusters[i].radius)) clusters[i] = d;
            return d;
        });

        var force = d3.layout.force()
            .nodes(nodes)
            .size([width, height])
            .gravity(0.52)
            .charge(0.02)
            .on("tick", tick)
            .start();

        var svg = d3.select("#bubbles").append("svg")
            .attr("width", width)
            .attr("height", height);

        var node = svg.selectAll("circle")
            .data(nodes)
            .enter().append("g").call(force.drag);
                node.append("circle")
                .style("fill", '#efeeeb')
                node.append("text")
                .text(function (d) {
                    return d.name;
                })

            .text(function (d) {
                return d.name
            })
            .style("fill", "black");

        svg.on("click", function() {
          force.resume();
        });

        function tick(e) {
            node.each(cluster(0.5*e.alpha * e.alpha))
                .each(collide(0.25))
            .attr("transform", function (d) {
                var k = "translate("   d.x   ","   d.y   ")";
                return k;
            })
        }

        // Move d to be adjacent to the cluster node.
        function cluster(alpha) {
            return function (d) {
                var cluster = clusters[d.cluster];
                if (cluster === d) return;
                var x = d.x - cluster.x,
                    y = d.y - cluster.y,
                    l = Math.sqrt(x * x   y * y),
                    r = d.radius   cluster.radius;
                if (l != r) {
                    l = (l - r) / l * alpha;
                    d.x -= x *= l;
                    d.y -= y *= l;
                    cluster.x  = x;
                    cluster.y  = y;
                }
            };
        }

        // Resolves collisions between d and all other circles.
        var ID=0;
        function collide(alpha) {
            var quadtree = d3.geom.quadtree(nodes);
            return function (d) {
                var r = d.radius   maxRadius   Math.max(padding, clusterPadding),
                    nx1 = d.x - r,
                    nx2 = d.x   r,
                    ny1 = d.y - r,
                    ny2 = d.y   r;
                quadtree.visit(function (quad, x1, y1, x2, y2) {
                    if (quad.point amp;amp; (quad.point !== d)) {
                        var x = d.x - quad.point.x,
                            y = d.y - quad.point.y,
                            l = Math.sqrt(x * x   y * y),
                            r = d.radius   quad.point.radius   (d.cluster === quad.point.cluster ? padding : clusterPadding);
                        if (l < r) {
                            l = (l - r) / l * alpha;
                            d.x -= x *= l;
                            d.y -= y *= l;
                            quad.point.x  = x;
                            quad.point.y  = y;
                        }
                    }
                    return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
                });
            };
        }

            var SVG = document.getElementsByTagName('svg')[0]
            var children = SVG.childNodes;

            [].forEach.call(children, function (child) {
                if(child.nodeType === 1 amp;amp; child.tagName == "g"){
                     child.setAttribute('class', 'normal');
                    child.setAttribute('id', 'g' ID);
                    ID  ;
                }
                $('#totalBubbles').val(ID);
            });

            // click event to change appearance of circle
            $('#bubbles').on('click', '.normal', function () {
                $(this).find('circle').css({ fill: "#ffcc00" });
                $(this).find('circle').attr('r', 34);
                force.resume();
              });

            // long press event to reduce circle size
                $('#bubbles').on('press', '.normal', function () {
                    $(this).find('circle').css({ fill: '#595959' });
                    $(this).find('circle').attr('r', 20);
                    $(this).find('text').css('font-size',"6px");
                });

        var labels = ["One",'Two','three','Four','Five','Six','Seven','Eight','Nine','Ten','Eleven','Twelve','Apple','Banana','Carrot','Onion','Beans'];

        var z=0;
        $('g').each(function () {
            $(this).find('text').html(labels[z]);
                    $(this).find('circle').attr('r', 36);
                    $(this).find('text').attr("text-anchor","middle").attr("alignment-baseline","central");
            z  ;
        });
    });//]]>
</script>


</head>

<body>

    <div id='bubbles'></div>
https://jsfiddle.net/amkdhpst/
</body>

</html>
  

Я создал JSFiddle здесь: JS FIddle

Заранее большое спасибо за любые указания

Дэвид

Ответ №1:

Лучше всего было бы использовать D3.js обработчики событий для управления событием щелчка и полного удаления обработчиков щелчков jQuery. Я изменил ваш узел var, чтобы он выглядел следующим образом:

 var node = svg.selectAll("circle")
    .data(nodes)
    .enter().append("g").call(force.drag);
        node.append("circle")
        .style("fill", '#efeeeb')
        .on("click", function() {
            d3.select(this)
          .style("fill", '#ffcc00')
          .attr("r", 25)                  
        });
  

Обновленная скрипка

Комментарии:

1. Большое спасибо за ответ. Я пробовал ваш обновленный JSFiddle и использовал ваш код на своей странице, но пузырьки по-прежнему занимают место своего первоначального размера. Кажется, что это быстрее и чище (и без JQ), но, похоже, это не способствует закрытию диаграммы после изменения размера пузырька : (

2. Ах, моя ошибка. Я понял, что вопрос заключается в том, как изменить размер кругов по щелчку, а не в том, как изменить размер пространства, которое они занимают. Чтобы уменьшить занимаемое пространство, вам придется перезапустить принудительный алгоритм при нажатии (например, вызвать force.start() при обратном вызове click). Я думаю, что ваш пользовательский кластерный алгоритм должен был бы учитывать размер кругов. Возможно, что готовый метод force.charge () полезен для ваших целей — это может упростить работу, не требуя вашего пользовательского алгоритма.