diff --git a/src/traces/table/constants.js b/src/traces/table/constants.js index cf24a0f2110..2ffde16af90 100644 --- a/src/traces/table/constants.js +++ b/src/traces/table/constants.js @@ -9,26 +9,27 @@ 'use strict'; module.exports = { - maxDimensionCount: 60, - overdrag: 45, cellPad: 8, + columnExtentOffset: 10, + columnTitleOffset: 28, + emptyHeaderHeight: 16, latexCheck: /^\$.*\$$/, - wrapSplitCharacter: ' ', - wrapSpacer: ' ', - lineBreaker: '
', - uplift: 5, goldenRatio: 1.618, - columnTitleOffset: 28, - columnExtentOffset: 10, - transitionEase: 'cubic-out', - transitionDuration: 100, - releaseTransitionEase: 'cubic-out', + lineBreaker: '
', + maxDimensionCount: 60, + overdrag: 45, releaseTransitionDuration: 120, - scrollbarWidth: 8, + releaseTransitionEase: 'cubic-out', scrollbarCaptureWidth: 18, - scrollbarOffset: 5, scrollbarHideDelay: 1000, scrollbarHideDuration: 1000, + scrollbarOffset: 5, + scrollbarWidth: 8, + transitionDuration: 100, + transitionEase: 'cubic-out', + uplift: 5, + wrapSpacer: ' ', + wrapSplitCharacter: ' ', cn: { // general class names table: 'table', diff --git a/src/traces/table/data_preparation_helper.js b/src/traces/table/data_preparation_helper.js index 25ca7ca5387..9e91767231c 100644 --- a/src/traces/table/data_preparation_helper.js +++ b/src/traces/table/data_preparation_helper.js @@ -14,14 +14,17 @@ var isNumeric = require('fast-isnumeric'); // pure functions, don't alter but passes on `gd` and parts of `trace` without deep copying module.exports = function calc(gd, trace) { + var cellsValues = trace.cells.values; + var slicer = function(a) { + return a.slice(trace.header.values.length, a.length); + }; var headerValues = trace.header.values.map(function(c) { return Array.isArray(c) ? c : [c]; - }); - var cellsValues = trace.cells.values; + }).concat(slicer(cellsValues).map(function() {return [''];})); var domain = trace.domain; var groupWidth = Math.floor(gd._fullLayout._size.w * (domain.x[1] - domain.x[0])); var groupHeight = Math.floor(gd._fullLayout._size.h * (domain.y[1] - domain.y[0])); - var headerRowHeights = headerValues.length ? headerValues[0].map(function() {return trace.header.height;}) : []; + var headerRowHeights = trace.header.values.length ? headerValues[0].map(function() {return trace.header.height;}) : [c.emptyHeaderHeight]; var rowHeights = cellsValues.length ? cellsValues[0].map(function() {return trace.cells.height;}) : []; var headerHeight = headerRowHeights.reduce(function(a, b) {return a + b;}, 0); var scrollHeight = groupHeight - headerHeight; @@ -31,7 +34,7 @@ module.exports = function calc(gd, trace) { var headerRowBlocks = makeRowBlock(anchorToHeaderRowBlock, []); var rowBlocks = makeRowBlock(anchorToRowBlock, headerRowBlocks); var uniqueKeys = {}; - var columnOrder = trace._fullInput.columnorder; + var columnOrder = trace._fullInput.columnorder.concat(slicer(cellsValues.map(function(d, i) {return i;}))); var columnWidths = headerValues.map(function(d, i) { var value = Array.isArray(trace.columnwidth) ? trace.columnwidth[Math.min(i, trace.columnwidth.length - 1)] : diff --git a/src/traces/table/data_split_helpers.js b/src/traces/table/data_split_helpers.js index 3f62666cc49..7ea90d4c07d 100644 --- a/src/traces/table/data_split_helpers.js +++ b/src/traces/table/data_split_helpers.js @@ -51,7 +51,7 @@ exports.splitToPanels = function(d) { exports.splitToCells = function(d) { var fromTo = rowFromTo(d); - return d.values.slice(fromTo[0], fromTo[1]).map(function(v, i) { + return (d.values || []).slice(fromTo[0], fromTo[1]).map(function(v, i) { // By keeping identical key, a DOM node removal, creation and addition is spared, important when visible // grid has a lot of elements (quadratic with xcol/ycol count). // But it has to be busted when `svgUtil.convertToTspans` is used as it reshapes cell subtrees asynchronously, diff --git a/test/jasmine/tests/table_test.js b/test/jasmine/tests/table_test.js index 5e599cd593e..2d532275963 100644 --- a/test/jasmine/tests/table_test.js +++ b/test/jasmine/tests/table_test.js @@ -206,6 +206,57 @@ describe('table', function() { }); }); + describe('Rendering with partial attribute support', function() { + var mockCopy, + gd; + + afterEach(destroyGraphDiv); + + it('`Plotly.plot` should render all the columns even if no cell contents were supplied yet', function(done) { + gd = createGraphDiv(); + mockCopy = Lib.extendDeep({}, mock); + delete mockCopy.data[0].cells; + Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(function() { + expect(gd.data.length).toEqual(1); + expect(gd.data[0].header.values.length).toEqual(7); + expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(7); + expect(document.querySelectorAll('.' + cn.columnCell).length).toEqual(7 * 2); // both column rows to render + done(); + }); + }); + + it('`Plotly.plot` should render all columns even if no header contents were supplied yet', function(done) { + gd = createGraphDiv(); + mockCopy = Lib.extendDeep({}, mock); + delete mockCopy.data[0].header; + Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(function() { + expect(gd.data.length).toEqual(1); + expect(gd.data[0].cells.values.length).toEqual(7); + expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(7); + expect(document.querySelectorAll('.' + cn.columnCell).length).toEqual(7 * 29); + expect(document.querySelectorAll('#header').length).toEqual(7); + expect(document.querySelectorAll('#header .' + cn.columnCell).length).toEqual(7); + expect(document.querySelector('#header .' + cn.columnCell + ' text').textContent).toEqual(''); + done(); + }); + }); + + it('`Plotly.plot` should render all the column headers even if not all header values were supplied', function(done) { + gd = createGraphDiv(); + mockCopy = Lib.extendDeep({}, mock); + mockCopy.data[0].header.values = ['A', 'S', 'D']; // doesn't cover all 7 columns + Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(function() { + expect(gd.data.length).toEqual(1); + expect(gd.data[0].cells.values.length).toEqual(7); + expect(document.querySelectorAll('.' + cn.yColumn).length).toEqual(7); + expect(document.querySelectorAll('#header').length).toEqual(7); + expect(document.querySelectorAll('#header .' + cn.columnCell).length).toEqual(7); + expect(document.querySelector('#header .' + cn.columnCell + ' text').textContent).toEqual('A'); + done(); + }); + }); + }); + describe('basic use and basic data restyling', function() { var mockCopy, gd;