d3js: событие щелчка в повторно используемой диаграмме

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

d3.cloudshapes.barChart = function module() {
    var margin = {top: 10, right: 10, bottom: 20, left: 20},
        width = 500,
        height = 500,
        gap = 0,
        ease = "bounce";
    var svg;


    // Define the 'inner' function: which, through the surreal nature of JavaScript scoping, can access
    // the above variables. 
    function exports(_selection) {
        _selection.each(function(_data) {
            var chartW = 60,
                chartH = 60;

        var test_data = _data.value;

            var x1 = d3.scale.ordinal()
                    .domain(test_data.map(function(d) { return d.x; }))
                    .rangeRoundBands([0, chartW], 0.1);

            var y1 = d3.scale.linear()
                    .domain([0, 36])
                    .range([chartH, 0]);

        var color = d3.scale.category10();

        // If no SVG exists, create one - and add key groups:
            if (!svg) {
                svg = d3.select(this)
                     .append("svg")
             .attr("width", width)
             .attr("height", height)
                     .classed("chart", true);
                var container = svg.append("g").classed("container-group", true);
                container.append("g").classed("chart-group", true);
        container.attr({transform: "translate(" + 60*_data.row + "," + 60*_data.col + ")"});
        container.on("click", click);

            }

        // Transition the width and height of the main SVG and the key 'g' group: 
            svg.classed("chart", true).transition().attr({width: width, height: height});
           var container = svg.append("g").classed("container-group", true);
        container.append("g").classed("chart-group", true);
        container.attr({transform: "translate(" + 60*_data.row + "," + 60*_data.col + ")"});

        container.on("click", click);

            function click()  {
                console.log("I got clicked");
            }

        // Define gap between bars: 
            var gapSize = x1.rangeBand() / 100 * gap;

        // Define width of each bar: 
            var barW = x1.rangeBand() - gapSize;

            // Select all bars and bind data:  
            var bars = svg.selectAll(".chart-group")
                        .selectAll(".bar")
                        .data(test_data);

        bars.enter().append("rect")
            .classed("bar", "true")
            .attr({
                width: barW,
                x: function (d) {                   
                    return x1(d.x) + gapSize / 2; },
                y: function(d) { return y1(d.y); },
                height: function(d) { return chartH - y1(d.y); }
        })
            .attr("fill", function(d) { return color(d.x); });



        });
    }

Но функция щелчка работает только для последнего экземпляра графика, отображаемого повторно используемой диаграммой. Как можно добавить прослушиватель кликов к каждому графику, отображаемому многократно используемой диаграммой??

Более простая версия находится здесь fiddle. Я хочу добавить увеличенную всплывающую гистограмму svg при нажатии на маленькие гистограммы. Я думаю, что проблема связана с динамически созданным div, потому что, когда я пытался создать диаграммы в предопределенном div, функция щелчка работала нормально.

Любая помощь приветствуется !


person user2398101    schedule 29.04.2014    source источник
comment
Вы запускаете этот код внутри компонента?   -  person Lars Kotthoff    schedule 29.04.2014
comment
@LarsKotthoff отредактировал код; container добавляется к SVG для создания элементов внутри графика.   -  person user2398101    schedule 29.04.2014
comment
@LarsKotthoff, что вы подразумеваете под «внутри компонента»?   -  person user2398101    schedule 29.04.2014
comment
Ну, предположительно у вас есть что-то похожее на element.call(component) для рендеринга компонента. Этот вызов также устанавливает прослушиватель событий или для этого нужно запускать отдельный код?   -  person Lars Kotthoff    schedule 29.04.2014
comment
@LarsKotthoff Это установит прослушиватель событий, но перед его реализацией я пробовал несколько простых журналов консоли, чтобы увидеть, как все работает.   -  person user2398101    schedule 29.04.2014
comment
Что ж, очень важно увидеть, как именно это реализовано, чтобы понять, почему это не работает.   -  person Lars Kotthoff    schedule 29.04.2014
comment
@LarsKotthoff Я добавил в вопрос код для многоразовой диаграммы. Я не могу поместить все это в скрипку, так как это много кода с базой данных.   -  person user2398101    schedule 29.04.2014
comment
Итак, если я правильно понимаю, вы будете передавать массив массивов этому компоненту, и он рисует гистограмму для каждого массива? Похоже, что селекторы там обращаются к элементам, созданным для более ранних гистограмм, что, вероятно, не то, что вам нужно. Однако код для установки прослушивателей событий выглядит нормально.   -  person Lars Kotthoff    schedule 29.04.2014
comment
@LarsKotthoff Да, я передаю массив массивов, который рисует каждую гистограмму, а затем преобразует и переводит ее в нужное место в svg, используя строку и столбец. Функция щелчка работает только для последнего созданного экземпляра диаграммы, поэтому может случиться так, что селектор просто обращается к последней диаграмме. Как бы вы порекомендовали исправить эту проблему селекторов??   -  person user2398101    schedule 30.04.2014
comment
@LarsKotthoff Я загрузил более простую рабочую скрипку на вопрос. Любые советы о том, как исправить проблему?   -  person user2398101    schedule 30.04.2014
comment
Честно говоря, я думаю, что здесь нужен рефакторинг. На мой взгляд, ваш компонент диаграммы должен отображать ровно одну гистограмму. Затем вы можете добавить несколько элементов и вызвать компонент несколько раз с разными данными. Это также должно решить проблему обработчика кликов.   -  person Lars Kotthoff    schedule 30.04.2014
comment
@LarsKotthoff Но я уже добавляю новые элементы chart-group и container-group для каждой гистограммы.   -  person user2398101    schedule 30.04.2014
comment
Я хочу сказать, что инкапсуляция каждой гистограммы по отдельности облегчит понимание того, с чем именно вы работаете. На данный момент вы добавляете элементы повсюду, и на них влияют элементы, добавленные ранее. Довольно сложно понять, что там происходит.   -  person Lars Kotthoff    schedule 30.04.2014
comment
@LarsKotthoff Прошу прощения, но сейчас я действительно запутался. Если я запускаю многоразовую диаграмму с двумя предопределенными div, то есть по одной для каждой диаграммы, функция клика отлично работает для обеих диаграмм. Он отлично работает, даже если обе диаграммы отображаются в одном предопределенном div. Итак, не будет ли ошибкой div, которые создаются динамически? Я должен создавать divs динамически, так как количество диаграмм зависит от данных, загруженных с конца пользователя, и не фиксируется.   -  person user2398101    schedule 30.04.2014
comment
Я не уверен, что ты имеешь в виду. Я думаю, что было бы лучше сделать итерацию, чтобы добавить несколько графиков не внутри компонента.   -  person Lars Kotthoff    schedule 30.04.2014
comment
@LarsKotthoff, эта скрипка должна прояснить ситуацию. Функция click работает нормально для обоих графиков, но как только строка document.getElemet() раскомментирована, та же проблема возникает снова. Это то, что я пытался сказать, что если я рисую диаграммы на предопределенных div, они работают нормально, но динамически созданные div создают ошибку.   -  person user2398101    schedule 30.04.2014
comment
Извините, какое отношение к этому имеет строка getElement()? Мне кажется, что это генерирует совершенно не связанную ошибку.   -  person Lars Kotthoff    schedule 30.04.2014
comment
@LarsKotthoff Простите, что снова беспокою вас, но я действительно застрял с этой функцией щелчка. Я изменил многоразовую диаграмму, чтобы нарисовать всю диаграмму за один вызов функции (как вы упомянули), но функция щелчка по-прежнему работает только для второй диаграммы. Это обновленная скрипта. Не могли бы вы взглянуть на него в последний раз ??   -  person user2398101    schedule 30.04.2014
comment
В вашем последнем jsfiddle ни одна из диаграмм, похоже, не запускает для меня обработчик событий щелчка.   -  person Lars Kotthoff    schedule 30.04.2014
comment
@LarsKotthoff Это странно, это работает для второй диаграммы на моей машине. Спасибо за проверку в любом случае !!   -  person user2398101    schedule 30.04.2014


Ответы (1)


Область действия переменной svg вызывает проблему. В вашем коде значение переменной svg является общим для всех экземпляров вашей многократно используемой функции. Вероятно, вы захотите использовать enter() для создания элемента SVG и внутренних компонентов, а также добавить прослушиватель click к компоненту. Переменная svg должна быть определена внутри функции exports.

// rest of the code...
function exports(selection) {
    selection.each(function(data) {

        // Select the SVG element
        var svg = d3.select(this).selectAll('svg').data([data]);

        // Create the SVG element on enter, set it's size
        svg.enter().append('svg')
            .attr('width', width)
            .attr('height', height);

        var component = svg.selectAll('g.component').data([data]);

        // Create the component group on enter and set its attributes
        component.enter().append('g');

        // Add other elements...

        // click listener
        component.on('click', function(d) {
            // click callback.
        });


    });
}
person Pablo Navarro    schedule 29.04.2014
comment
Я хочу иметь один svg для всех маленьких гистограмм. Я думаю, что проблема связана с динамически созданным div, потому что, когда я пытался создать несколько диаграмм в одном предопределенном div, функция щелчка для всех диаграмм работала нормально. Я прикрепил рабочую скрипку. Любая помощь приветствуется ! - person user2398101; 30.04.2014