From 53ba25b5b00cdff5b61d82470c89b8d0fdc7f7d4 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 4 Aug 2021 20:27:45 +0530 Subject: [PATCH] more chart visualizations, brand colors --- customize.dist/src/less2/include/charts.less | 10 ++ www/common/inner/charts.js | 18 ++- www/form/app-form.less | 4 + www/form/inner.js | 126 ++++++++++++++++--- www/test/inner.js | 44 ++++++- 5 files changed, 179 insertions(+), 23 deletions(-) create mode 100644 customize.dist/src/less2/include/charts.less diff --git a/customize.dist/src/less2/include/charts.less b/customize.dist/src/less2/include/charts.less new file mode 100644 index 000000000..684ff8a5f --- /dev/null +++ b/customize.dist/src/less2/include/charts.less @@ -0,0 +1,10 @@ +.charts_main() { + &.bar { + td { + margin-top: 0.25em; + background: @cryptpad_color_brand_fade !important; + color: @cryptpad_color_grey_100 !important; //text_col !important; + font-weight: bold; + } + } +} diff --git a/www/common/inner/charts.js b/www/common/inner/charts.js index c4d9d685a..54576d435 100644 --- a/www/common/inner/charts.js +++ b/www/common/inner/charts.js @@ -15,7 +15,7 @@ define([ h('tbody', rows.map(function (n) { return h('tr', h('td', { style: '--size: ' + (n / 100), - }, n)); + }, h('span.data', n))); })), ], [ 'charts-css', @@ -24,10 +24,18 @@ define([ ]); }; - Charts.row = function (text, count) { - return h('tr', h('td', { - style: '--size: ' + count, - }, text)); + Charts.row = function (text, count, data) { + return h('tr', [ + h('th', { + scope: 'row', + }, text), + h('td', { + style: '--size: ' + count, + }, [ + //text, + typeof(data) !== 'undefined'? h('span.data', data): text, + ]) + ]); }; // table.charts-css.bar.reverse diff --git a/www/form/app-form.less b/www/form/app-form.less index ad26863bb..2d6832222 100644 --- a/www/form/app-form.less +++ b/www/form/app-form.less @@ -1,6 +1,7 @@ @import (reference) '../../customize/src/less2/include/framework.less'; @import (reference) '../../customize/src/less2/include/tools.less'; @import (reference) '../../customize/src/less2/include/avatar.less'; +@import (reference) '../../customize/src/less2/include/charts.less'; &.cp-app-form { @form_input-width: 400px; @@ -797,5 +798,8 @@ } } + .charts-css { + .charts_main(); + } } diff --git a/www/form/inner.js b/www/form/inner.js index 02033885e..896e041e7 100644 --- a/www/form/inner.js +++ b/www/form/inner.js @@ -955,6 +955,10 @@ define([ }, }; + var arrayMax = function (A) { + return Array.isArray(A)? Math.max.apply(null, A): NaN; + }; + var TYPES = { // XXX hackathon insert useful charts for each of type of answer input: { defaultOpts: { @@ -1001,7 +1005,7 @@ define([ Util.inc(tally, answer); }); var counts = Util.values(tally); - var max = Math.max.apply(null, counts); + var max = arrayMax(counts); if (max < 2) { // there are no duplicates, so just return text Object.keys(answers).forEach(function (author) { @@ -1020,14 +1024,9 @@ define([ // there are duplicates, so return a bar chart var rows = []; // XXX Object.keys(tally).forEach(function (answer) { - console.error('answer: %s, count: %s', answer, tally[answer]); - rows.push(Charts.row(answer, tally[answer] / max)); + rows.push(Charts.row(answer, tally[answer] / max, tally[answer])); }); - if (empty) { // XXX - rows.push(row('XXX empty', empty)); - } - var table = Charts.table([ //h('caption', ''), // XXX h('tbody', rows) @@ -1035,9 +1034,14 @@ define([ 'charts-css', 'bar', 'show-heading', + 'show-labels', + 'show-data-on-hover', ]); - return h('div.cp-form-results-type-text', table); + return h('div.cp-form-results-type-text', [ + table, + empty? getEmpty(empty): undefined, + ]); }, icon: h('i.cptools.cptools-form-text') }, @@ -1177,11 +1181,11 @@ define([ }); var counts = Util.values(count); - var max = Math.max.apply(null, counts); + var max = arrayMax(counts); var rows = []; Object.keys(count).forEach(function (text) { - rows.push(Charts.row(text, count[text] / max)); + rows.push(Charts.row(text, count[text] / max, count[text])); }); var table = Charts.table([ @@ -1189,7 +1193,9 @@ define([ ], [ 'charts-css', 'bar', + 'show-labels', //'show-heading', + 'show-data-on-hover', ]); return h('div.cp-form-results-type-radio', { style: 'width: 100%', @@ -1301,9 +1307,39 @@ define([ Util.inc(c, res); }); }); - Object.keys(count).forEach(function (q_uid) { + + var max = 0; + var count_keys = Object.keys(count); + count_keys.forEach(function (q_uid) { + var counts = Object.values(count[q_uid]); + counts.push(max); + max = arrayMax(counts); + }); + + count_keys.forEach(function (q_uid) { var q = findItem(opts.items, q_uid); var c = count[q_uid]; + + var table = Charts.table([ + h('caption', { + style: 'color: var(--msg-color)', // XXX light/dark modes + }, q), + h('tbody', Object.keys(c).map(function (res) { + return Charts.row(res, c[res] / max, c[res]); + })), + ], [ + 'charts-css', + 'bar', + 'show-heading', + 'show-data-on-hover', + 'show-labels', + + ]); + + results.push(h('div.cp-form-results-type-multiradio-data', { + style: 'width: 100%', + }, table)); +/* var values = Object.keys(c).map(function (res) { return h('div.cp-form-results-type-radio-data', [ h('span.cp-value', res), @@ -1314,10 +1350,13 @@ define([ h('span.cp-mr-q', q), h('span.cp-mr-value', values) ])); +*/ }); results.push(getEmpty(empty)); - return h('div.cp-form-results-type-radio', results); + return h('div.cp-form-results-type-radio', { + style: 'width: 100%', + }, results); }, exportCSV: function (answer, form) { var opts = form.opts || {}; @@ -1400,7 +1439,7 @@ define([ }, printResults: function (answers, uid) { - // XXX hackathon multiradio https://chartscss.org/components/stacked/ + // XXX hackathon radio https://chartscss.org/charts/bar/ var results = []; var empty = 0; var count = {}; @@ -1509,7 +1548,7 @@ define([ }, printResults: function (answers, uid, form) { - // XXX hackathon + // XXX hackathon multicheck // stacked: https://chartscss.org/components/stacked/ // or multiple bars: https://chartscss.org/charts/bar/#multiple-datasets var structure = form[uid]; @@ -1531,9 +1570,38 @@ define([ }); }); }); - Object.keys(count).forEach(function (q_uid) { + + var max = 0; + var count_keys = Object.keys(count); + count_keys.forEach(function (q_uid) { + var counts = Object.values(count[q_uid]); + counts.push(max); + max = arrayMax(counts); + }); + + count_keys.forEach(function (q_uid) { var q = findItem(opts.items, q_uid); var c = count[q_uid]; + + var table = Charts.table([ + h('caption', { + style: 'color: var(--msg-color)', // XXX light/dark modes + }, q), + h('tbody', Object.keys(c).map(function (res) { + return Charts.row(res, c[res] / max, c[res]); + })), + ], [ + 'charts-css', + 'bar', + 'show-heading', + 'show-data-on-hover', + 'show-labels', + ]); + + results.push(h('div.cp-form-results-type-multiradio-data', { + style: 'width: 100%', + }, table)); +/* var values = Object.keys(c).map(function (res) { return h('div.cp-form-results-type-radio-data', [ h('span.cp-value', res), @@ -1544,10 +1612,13 @@ define([ h('span.cp-mr-q', q), h('span.cp-mr-value', values) ])); +*/ }); results.push(getEmpty(empty)); - return h('div.cp-form-results-type-radio', results); + return h('div.cp-form-results-type-radio', { + style: 'width: 100%', + }, results); }, exportCSV: function (answer, form) { var opts = form.opts || {}; @@ -1670,6 +1741,29 @@ define([ Util.inc(count, el, score); }); }); + var counts = Util.values(count); + var max = arrayMax(counts); + + var rows = []; + Object.keys(count).forEach(function (text) { + rows.push(Charts.row(text, count[text] / max, count[text])); + }); + + var table = Charts.table([ + h('tbody', rows), + ], [ + 'charts-css', + 'bar', + 'show-labels', + 'show-data-on-hover', + //'show-heading', + ]); + + return h('div.cp-form-results-type-radio', { + style: 'width: 100%', + }, table); + + var sorted = Object.keys(count).sort(function (a, b) { return count[b] - count[a]; }); diff --git a/www/test/inner.js b/www/test/inner.js index f7fdbc2d2..4b02d51a1 100644 --- a/www/test/inner.js +++ b/www/test/inner.js @@ -13,16 +13,56 @@ define([ }; var data = [ - 25, 58, 0, 96, 79, + 25, 58, 5, 96, 79, 23, 75, 13, 44, 29, 65, 80, 30, 47, 22, 7, 62, 64, 46, 21, 29, 31, 76, 65, 61, 78, 58, 12, 90, 98, 37, 75, 92, 74, 16, - 0, 52, 42, 71, 19 + 17, 52, 42, 71, 19 ]; + + append(h('h1', 'Charts')); + append(h('hr')); + + var cell = (function () { + var i = 0; + + return function () { + var val = data[i++]; + return h('td', { + style: '--size: ' + (val / 100), + }, val); + }; + }()); + + var multirow = function (n) { + var cells = []; + while (n--) { + cells.push(cell()); + } + return h('tr', { + style: 'margin: 15px', + }, cells); + }; + + append(wrap(Charts.table([ + h('tbody', [ + multirow(4), + multirow(4), + multirow(4), + multirow(4), + ]), + ], [ + 'charts-css', + 'bar', + 'multiple', + ]))); + + + append(h('hr')); append(wrap(Charts.columns([ 40, 60, 75, 90, 100]))); append(wrap(Charts.columns(data.slice(20)))); });