Подтвердить что ты не робот

D3 добавление атрибута данных условно

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

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

var th = d3.select(selection).select("thead").selectAll("th")
            .data(colspec)
            .enter().append("th")
            .text(function(d) { return d["data-name"]; })
            .attr("data-class", function(d) {
                if ("data-class" in d) {
                    return d["data-class"];
                } else {
                    return "";
                }
            })
            .attr("data-hide", function(d) {
                if ("data-hide" in d) {
                    return d["data-hide"];
                } else {
                    return "";
                }
            })
            .attr("data-ignore", function(d) {
                if ("data-ignore" in d) {
                    return d["data-ignore"];
                } else {
                    return "";
                }
            })

       etc.

Пример colspec:

[{"data-name": "username"}, {"data-name": "Date Joined", "data-hide": "true"}]

В настоящее время получается:

  <th data-class="" data-hide="true" data-ignore="" data-type="">Joined</th>

Want

   <th  data-hide="true" >Joined</th>

Любые предложения?

4b9b3361

Ответ 1

Кажется хорошим кандидатом для .each():

var th = d3.select(selection).select("thead").selectAll("th")
        .data(colspec)
    .enter().append("th")
        .text(function(d) { return d["data-name"]; })
        // now address each item individually
        .each(function(d) {
            var header = d3.select(this);
            // loop through the keys - this assumes no extra data
            d3.keys(d).forEach(function(key) {
                if (key != "data-name")
                    header.attr(key, d[key]);
            });
        });

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

Для краткого списка атрибутов, особенно если вы беспокоитесь о дополнительных данных в объектах, возможно, проще всего перебрать нужные ключи, а не все:

        .each(function(d) {
            var header = d3.select(this);
            ['data-class', 'data-hide', 'data-ignore'].forEach(function(key) {
                if (key in d)
                    header.attr(key, d[key]);
            });
        });

Ответ 2

Вам не нужно вызывать each() или filter()... Функция attr() сделает это для вас внутренне. Просто вызовите его с помощью функции вместо значения, и эта функция вернет желаемое значение для каждой точки привязки или null, если атрибут не нужен для конкретной привязки, например:

...
.attr('data-class', function(d) {
    return 'data-class' in d ? d['data-class'] : null;
});

Если ваша функция возвращает значение null, атрибут не добавляется. Вы даже можете объединить несколько атрибутов в один вызов, предоставив карту имен attr для таких функций:

...
.attr({
    'data-class': function(d) {
        return 'data-class' in d ? d['data-class'] : null;
    }, 
    'data-hide': function(d) {
        return 'data-hide' in d ? d['data-hide'] : null;
    },
    'data-ignore': function(d) {
        return 'data-ignore' in d ? d['data-ignore'] : null;
    }
});

или если вы похожи на меня и не хотите вводить так много, вы можете уменьшить список имен атрибутов в соответствующей карте:

...
.attr(['data-class', 'data-hide', 'data-ignore'].reduce(function(result, attr) {
    result[attr] = function(d) {
        return attr in d ? d[attr] : null;
    }
    return result;
}, {}));

Ответ 3

Вы можете использовать функцию .filter() только для работы с подмножеством выделения, которое вам нужно установить для атрибутов, например

var th = d3.select(selection).select("thead").selectAll("th")
        .data(colspec)
        .enter().append("th")
        .text(function(d) { return d["data-name"]; });
th.filter(function(d) { return ("data-class" in d); })
        .attr("data-class", function(d) {
            return d["data-class"];
        });

Ответ 4

Очиститель должен использовать фильтр

.filter(d => !!d["data-class"]) // filter only data with the "data-class" property
.attr("data-class", d => d["data-class"])