From 951ce8a937ec13992f421ee161687b5f7ce5e3bd Mon Sep 17 00:00:00 2001 From: Robert Monfera Date: Wed, 31 Jan 2018 21:41:04 +0100 Subject: [PATCH 1/5] table `values` may be left unspecified --- src/traces/table/data_split_helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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, From 66b88d65bc8475226bbb4b0db426875b31e089f6 Mon Sep 17 00:00:00 2001 From: Robert Monfera Date: Wed, 31 Jan 2018 22:37:46 +0100 Subject: [PATCH 2/5] table `values` may be left unspecified - test case --- test/jasmine/tests/table_test.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/jasmine/tests/table_test.js b/test/jasmine/tests/table_test.js index 5e599cd593e..c371170dc98 100644 --- a/test/jasmine/tests/table_test.js +++ b/test/jasmine/tests/table_test.js @@ -206,6 +206,29 @@ describe('table', function() { }); }); + describe('Rendering with partial attribute support', function() { + var mockCopy, + gd; + + beforeEach(function(done) { + mockCopy = Lib.extendDeep({}, mock); + mockCopy.data[0].domain = { + x: [0.1, 0.9], + y: [0.05, 0.85] + }; + delete mockCopy.data[0].cells; + gd = createGraphDiv(); + Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(done); + }); + + it('`Plotly.plot` should render all the columns even if no cell contents were supplied yet', 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 + }); + }); + describe('basic use and basic data restyling', function() { var mockCopy, gd; From c3f0908a04a67e5dd47d2f4dca72a81125d16217 Mon Sep 17 00:00:00 2001 From: Robert Monfera Date: Fri, 2 Feb 2018 19:36:08 +0100 Subject: [PATCH 3/5] filling up column header cells with the empty string; column order extension --- src/traces/table/data_preparation_helper.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/traces/table/data_preparation_helper.js b/src/traces/table/data_preparation_helper.js index 25ca7ca5387..c7430b21715 100644 --- a/src/traces/table/data_preparation_helper.js +++ b/src/traces/table/data_preparation_helper.js @@ -14,10 +14,13 @@ 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])); @@ -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)] : From 0682a886437628c9c98bf90d942ba07fefca6750 Mon Sep 17 00:00:00 2001 From: Robert Monfera Date: Sat, 3 Feb 2018 22:05:15 +0100 Subject: [PATCH 4/5] add a shorter default header when there's no header specified --- src/traces/table/constants.js | 27 +++++++++++---------- src/traces/table/data_preparation_helper.js | 2 +- 2 files changed, 15 insertions(+), 14 deletions(-) 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 c7430b21715..9e91767231c 100644 --- a/src/traces/table/data_preparation_helper.js +++ b/src/traces/table/data_preparation_helper.js @@ -24,7 +24,7 @@ module.exports = function calc(gd, trace) { 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; From c786ade47de6863a765ba1708be0713ab8af1247 Mon Sep 17 00:00:00 2001 From: Robert Monfera Date: Sun, 4 Feb 2018 19:08:05 +0100 Subject: [PATCH 5/5] test cases for unsupplied or partially supplied column headers --- test/jasmine/tests/table_test.js | 50 +++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/test/jasmine/tests/table_test.js b/test/jasmine/tests/table_test.js index c371170dc98..2d532275963 100644 --- a/test/jasmine/tests/table_test.js +++ b/test/jasmine/tests/table_test.js @@ -210,22 +210,50 @@ describe('table', function() { var mockCopy, gd; - beforeEach(function(done) { + 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); - mockCopy.data[0].domain = { - x: [0.1, 0.9], - y: [0.05, 0.85] - }; 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(); - Plotly.plot(gd, mockCopy.data, mockCopy.layout).then(done); + 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 columns even if no cell contents were supplied yet', 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 + 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(); + }); }); });