From 73acfd9b429298abc175f65b2fb78dff897e3a60 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 4 Aug 2021 17:08:29 +0530 Subject: [PATCH] start integrating some basic charts in form answers --- www/common/common-util.js | 6 ++++ www/common/inner/charts.js | 14 +++++++- www/form/inner.js | 72 ++++++++++++++++++++++++++++++++++---- www/test/inner.js | 3 +- 4 files changed, 85 insertions(+), 10 deletions(-) diff --git a/www/common/common-util.js b/www/common/common-util.js index ac50a1f24..3d2a8d0a4 100644 --- a/www/common/common-util.js +++ b/www/common/common-util.js @@ -165,6 +165,12 @@ map[key] = (map[key] || 0) + (typeof(val) === 'number'? val: 1); }; + Util.values = function (obj) { + return Object.keys(obj).map(function (k) { + return obj[k]; + }); + }; + Util.find = function (map, path) { var l = path.length; for (var i = 0; i < l; i++) { diff --git a/www/common/inner/charts.js b/www/common/inner/charts.js index a50939530..c4d9d685a 100644 --- a/www/common/inner/charts.js +++ b/www/common/inner/charts.js @@ -24,11 +24,23 @@ define([ ]); }; + Charts.row = function (text, count) { + return h('tr', h('td', { + style: '--size: ' + count, + }, text)); + }; + // table.charts-css.bar.reverse - // Charts.bars +/* + Charts.bars = function (rows) { + return Charts.table([ + ], [ + ]); + }; +*/ return Charts; }); diff --git a/www/form/inner.js b/www/form/inner.js index 6ff0ccded..02033885e 100644 --- a/www/form/inner.js +++ b/www/form/inner.js @@ -38,6 +38,7 @@ define([ 'css!/bower_components/codemirror/addon/dialog/dialog.css', 'css!/bower_components/codemirror/addon/fold/foldgutter.css', 'css!/lib/datepicker/flatpickr.min.css', + 'css!/lib/chart/charts.min.css', 'css!/bower_components/components-font-awesome/css/font-awesome.min.css', 'less!/form/app-form.less', ], function ( @@ -991,17 +992,52 @@ define([ printResults: function (answers, uid) { // XXX hackathon each question format has a 'printResults' method var results = []; var empty = 0; - // XXX hackathon charts for text inputs are only useful if we tally duplicated answers - // XXX hackathon use horizontal bar charts https://chartscss.org/charts/bar/ - Object.keys(answers).forEach(function (author) { // TODO deduplicate these? + var tally = {}; + + Object.keys(answers).forEach(function (author) { var obj = answers[author]; var answer = obj.msg[uid]; if (!answer || !answer.trim()) { return empty++; } - results.push(h('div.cp-form-results-type-text-data', answer)); + Util.inc(tally, answer); }); - results.push(getEmpty(empty)); + var counts = Util.values(tally); + var max = Math.max.apply(null, counts); + + if (max < 2) { // there are no duplicates, so just return text + Object.keys(answers).forEach(function (author) { + var obj = answers[author]; + var answer = obj.msg[uid]; + if (!answer || !answer.trim()) { return empty++; } + results.push(h('div.cp-form-results-type-text-data', answer)); + }); + results.push(getEmpty(empty)); + return h('div.cp-form-results-type-text', results); + } - return h('div.cp-form-results-type-text', results); + // increase the scale of the bar chart if there are more empty answers than anything else + max = Math.max(max, empty); + + // 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)); + }); + + if (empty) { // XXX + rows.push(row('XXX empty', empty)); + } + + var table = Charts.table([ + //h('caption', ''), // XXX + h('tbody', rows) + ], [ + 'charts-css', + 'bar', + 'show-heading', + ]); + + return h('div.cp-form-results-type-text', table); }, icon: h('i.cptools.cptools-form-text') }, @@ -1139,15 +1175,37 @@ define([ if (!answer || !answer.trim()) { return empty++; } Util.inc(count, answer); }); + + var counts = Util.values(count); + var max = Math.max.apply(null, counts); + var rows = []; + + Object.keys(count).forEach(function (text) { + rows.push(Charts.row(text, count[text] / max)); + }); + + var table = Charts.table([ + h('tbody', rows) + ], [ + 'charts-css', + 'bar', + //'show-heading', + ]); + return h('div.cp-form-results-type-radio', { + style: 'width: 100%', + }, table); + +/* Object.keys(count).forEach(function (value) { results.push(h('div.cp-form-results-type-radio-data', [ h('span.cp-value', value), h('span.cp-count', count[value]) ])); }); - results.push(getEmpty(empty)); + results.push(getEmpty(empty)); // XXX show number of empty answers return h('div.cp-form-results-type-radio', results); +*/ }, icon: h('i.cptools.cptools-form-list-radio') }, diff --git a/www/test/inner.js b/www/test/inner.js index 5986f7c01..f7fdbc2d2 100644 --- a/www/test/inner.js +++ b/www/test/inner.js @@ -1,8 +1,7 @@ define([ '/common/hyperscript.js', '/common/inner/charts.js', - '/common/common-util.js', -], function (h, Charts, Util) { +], function (h, Charts) { var wrap = function (content) { return h('div', { style: 'height: 500px; width: 500px; padding: 15px; border: 1px solid #222; margin: 15px;'