UNPKG

d3-metatable

Version:

a table element for heterogenous objects

255 lines (212 loc) 9.13 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-selection'), require('d3-dispatch'), require('d3-array'), require('d3-collection')) : typeof define === 'function' && define.amd ? define(['exports', 'd3-selection', 'd3-dispatch', 'd3-array', 'd3-collection'], factory) : (factory((global.d3 = global.d3 || {}),global.d3,global.d3,global.d3,global.d3)); }(this, (function (exports,d3Selection,d3Dispatch,d3Array,d3Collection) { 'use strict'; var metatable = function (options) { var dispatcher = d3Dispatch.dispatch('change', 'rowfocus', 'renameprompt', 'deleteprompt'); var _renamePrompt = true; var _deletePrompt = true; options = options || {}; var config = { newCol: options.newCol !== false, renameCol: options.renameCol !== false, deleteCol: options.deleteCol !== false }; function table(selection) { selection.each(function(d) { var sel = d3Selection.select(this), table; var keyset = d3Collection.set(); d.map(Object.keys).forEach(function(k) { k.forEach(function(_) { keyset.add(_); }); }); var keys = keyset.values(); bootstrap(); paint(); dispatcher.preventprompt = function(which) { switch(which) { case 'rename': _renamePrompt = false; break; case 'delete': _deletePrompt = false; break; } }; function bootstrap() { var controls = sel .selectAll('.controls') .data([d]) .enter() .append('div') .attr('class', 'controls'); if (config.newCol) { controls.append('a') .text('New column') .attr('href', '#') .attr('class', 'button icon plus') .on('click', function() { d3Selection.event.preventDefault(); var name = prompt('column name'); if (name) { keys.push(name); paint(); } }); } var enter = sel.selectAll('table').data([d]).enter().append('table'); var thead = enter.append('thead'); var tbody = enter.append('tbody'); var tr = thead.append('tr'); table = sel.select('table'); } function paint() { var th = table .select('thead') .select('tr') .selectAll('th') .data(keys, function(d) { return d; }); th.exit().remove(); var thEnter = th.enter() .append('th') .text(String); var actionLinks = thEnter .append('div') .attr('class', 'small'); if (config.deleteCol) { actionLinks .append('a') .attr('href', '#') .attr('class', 'icon trash') .text('Delete') .on('click', deleteClick); } if (config.renameCol) { actionLinks .append('a') .attr('href', '#') .attr('class', 'icon pencil') .text('Rename') .on('click', renameClick); } var tr = table.select('tbody').selectAll('tr') .data(function(d) { return d; }); tr.exit().remove(); tr = tr.enter().append('tr').merge(tr); var td = tr.selectAll('td') .data(keys, function(d) { return d; }); td.exit().remove(); td.enter() .append('td') .append('textarea') .attr('field', String); function deleteClick(d) { d3Selection.event.preventDefault(); var name = d; dispatcher.call('deleteprompt', dispatcher, d, completeDelete); if (_deletePrompt && confirm('Delete column ' + name + '?')) { completeDelete(d); } _deletePrompt = true; } function completeDelete(name) { keys.splice(keys.indexOf(name), 1); tr.selectAll('textarea') .data(function(d, i) { var m = d3Collection.map(d); m.remove(name); var reduced = mapToObject(m); dispatcher.call('change', dispatcher, reduced, i); return { data: reduced, index: i }; }); paint(); } function renameClick(d) { d3Selection.event.preventDefault(); var name = d; dispatcher.call('renameprompt', dispatcher, d, completeRename); var newname = (_renamePrompt) ? prompt('New name for column ' + name + '?') : undefined; if (_renamePrompt && newname) { completeRename(newname, name); } _renamePrompt = true; } function completeRename(value, name) { keys.splice(keys.indexOf(name), 1, value); tr.selectAll('textarea') .data(function(d, i) { var m = d3Collection.map(d); m.set(value, m.get(name)); m.remove(name); var reduced = mapToObject(m); dispatcher.call('change', dispatcher, reduced, i); return { data: reduced, index: i }; }); paint(); } function coerceNum(x) { var fl = parseFloat(x); if (fl.toString() === x) return fl; else return x; } function write(d) { d.data[d3Selection.select(this).attr('field')] = coerceNum(this.value); dispatcher.call('change', dispatcher, d.data, d.index); } function mapToObject(m) { return m.entries() .reduce(function(memo, d) { memo[d.key] = d.value; return memo; }, {}); } tr.selectAll('textarea') .data(function(d, i) { return d3Array.range(keys.length).map(function() { return { data: d, index: i }; }); }) .classed('disabled', function(d) { return d.data[d3Selection.select(this).attr('field')] === undefined; }) .property('value', function(d) { var value = d.data[d3Selection.select(this).attr('field')]; return !isNaN(value) ? value : value || ''; }) .on('keyup', write) .on('change', write) .on('click', function(d) { if (d.data[d3Selection.select(this).attr('field')] === undefined) { d.data[d3Selection.select(this).attr('field')] = ''; paint(); } }) .on('focus', function(d) { dispatcher.call('rowfocus', dispatcher, d.data, d.index); }); } }); } table.on = function () { dispatcher.on.apply(dispatcher, arguments); return table; }; return table; }; exports.metatable = metatable; Object.defineProperty(exports, '__esModule', { value: true }); })));