feat(poll annotations): better annotation layout
This commit is contained in:
parent
1ef1084fcb
commit
d6ab158d18
@ -5,6 +5,8 @@ import { defineMessages } from 'react-intl';
|
||||
|
||||
const POLL_AVATAR_COLOR = '#3B48A9';
|
||||
const MAX_POLL_RESULT_BARS = 20;
|
||||
const MAX_POLL_RESULT_KEY_LENGTH = 10;
|
||||
const POLL_BAR_CHAR = '\u220E';
|
||||
|
||||
// 'YN' = Yes,No
|
||||
// 'YNA' = Yes,No,Abstention
|
||||
@ -116,6 +118,18 @@ const generatePossibleLabels = (alphabetCharacters) => {
|
||||
return possibleLabels;
|
||||
};
|
||||
|
||||
const truncate = (text, length) => {
|
||||
let resultText = text;
|
||||
if (resultText.length < length) {
|
||||
const diff = length - resultText.length;
|
||||
const padding = ' '.repeat(diff);
|
||||
resultText += padding;
|
||||
} else if (resultText.length > length) {
|
||||
resultText = `${resultText.substring(0, MAX_POLL_RESULT_KEY_LENGTH - 3)}...`;
|
||||
}
|
||||
return resultText;
|
||||
};
|
||||
|
||||
const getPollResultsText = (isDefaultPoll, answers, numRespondents, intl) => {
|
||||
let responded = 0;
|
||||
let resultString = '';
|
||||
@ -132,29 +146,36 @@ const getPollResultsText = (isDefaultPoll, answers, numRespondents, intl) => {
|
||||
)
|
||||
: false;
|
||||
|
||||
let longestKeyLength = answers.reduce(
|
||||
(acc, item) => (item.key.length > acc ? item.key.length : acc), 0,
|
||||
);
|
||||
longestKeyLength = Math.min(longestKeyLength, MAX_POLL_RESULT_KEY_LENGTH);
|
||||
|
||||
answers.map((item) => {
|
||||
responded += item.numVotes;
|
||||
return item;
|
||||
}).forEach((item, index) => {
|
||||
const numResponded = responded === numRespondents ? numRespondents : responded;
|
||||
const pct = Math.round((item.numVotes / numResponded) * 100);
|
||||
const pctBars = '|'.repeat((pct * MAX_POLL_RESULT_BARS) / 100);
|
||||
const pct = Math.round((item.numVotes / (numResponded || 1)) * 100);
|
||||
const pctBars = POLL_BAR_CHAR.repeat((pct * MAX_POLL_RESULT_BARS) / 100);
|
||||
const pctFotmatted = `${Number.isNaN(pct) ? 0 : pct}%`;
|
||||
if (isDefaultPoll) {
|
||||
const translatedKey = pollAnswerIds[item.key.toLowerCase()]
|
||||
let translatedKey = pollAnswerIds[item.key.toLowerCase()]
|
||||
? intl.formatMessage(pollAnswerIds[item.key.toLowerCase()])
|
||||
: item.key;
|
||||
resultString += `${translatedKey}: ${item.numVotes || 0} |${pctBars} ${pctFotmatted}\n`;
|
||||
translatedKey = truncate(translatedKey, longestKeyLength);
|
||||
resultString += `${translatedKey}: ${item.numVotes || 0} ${pctBars}${POLL_BAR_CHAR} ${pctFotmatted}\n`;
|
||||
} else {
|
||||
if (isPollAnswerMatchFormat) {
|
||||
resultString += `${pollAnswerMatchLabeledFormat[index][0]}`;
|
||||
const formattedAnswerValue = getFormattedAnswerValue(item.key);
|
||||
optionsString += `${pollAnswerMatchLabeledFormat[index][0]}: ${formattedAnswerValue}\n`;
|
||||
} else {
|
||||
resultString += `${item.id + 1}`;
|
||||
optionsString += `${item.id + 1}: ${item.key}\n`;
|
||||
let { key } = item;
|
||||
key = truncate(key, longestKeyLength);
|
||||
resultString += key;
|
||||
}
|
||||
resultString += `: ${item.numVotes || 0} |${pctBars} ${pctFotmatted}\n`;
|
||||
resultString += `: ${item.numVotes || 0} ${pctBars}${POLL_BAR_CHAR} ${pctFotmatted}\n`;
|
||||
}
|
||||
});
|
||||
|
||||
@ -170,16 +191,16 @@ const getPollResultString = (pollResultData, intl) => {
|
||||
const sanitize = (value) => escapeHtml(value);
|
||||
|
||||
const { answers, numRespondents, questionType } = pollResultData;
|
||||
const ísDefault = isDefaultPoll(questionType);
|
||||
const isDefault = isDefaultPoll(questionType);
|
||||
let {
|
||||
resultString,
|
||||
optionsString,
|
||||
} = getPollResultsText(ísDefault, answers, numRespondents, intl);
|
||||
} = getPollResultsText(isDefault, answers, numRespondents, intl);
|
||||
resultString = sanitize(resultString);
|
||||
optionsString = sanitize(optionsString);
|
||||
|
||||
let pollText = formatBoldBlack(resultString);
|
||||
if (!ísDefault) {
|
||||
if (optionsString !== '') {
|
||||
pollText += formatBoldBlack(`<br/><br/>${intl.formatMessage(intlMessages.legendTitle)}<br/>`);
|
||||
pollText += optionsString;
|
||||
}
|
||||
@ -311,4 +332,5 @@ export default {
|
||||
validateInput,
|
||||
removeEmptyLineSpaces,
|
||||
getSplittedQuestionAndOptions,
|
||||
POLL_BAR_CHAR,
|
||||
};
|
||||
|
@ -176,6 +176,7 @@ const formatAnnotations = (annotations, intl, curPageId, currentPresentationPage
|
||||
if (annotationInfo.questionType) {
|
||||
// poll result, convert it to text and create tldraw shape
|
||||
if (!annotationInfo.props) {
|
||||
const { POLL_BAR_CHAR } = PollService;
|
||||
annotationInfo.answers = annotationInfo.answers.reduce(
|
||||
caseInsensitiveReducer, [],
|
||||
);
|
||||
@ -185,13 +186,13 @@ const formatAnnotations = (annotations, intl, curPageId, currentPresentationPage
|
||||
const lines = pollResult.split('\n');
|
||||
const longestLine = lines.reduce((a, b) => (a.length > b.length ? a : b), '').length;
|
||||
|
||||
// add empty spaces before first | in each of the lines to make them all the same length
|
||||
// add empty spaces after last ∎ in each of the lines to make them all the same length
|
||||
pollResult = lines.map((line) => {
|
||||
if (!line.includes('|') || line.length === longestLine) return line;
|
||||
if (!line.includes(POLL_BAR_CHAR) || line.length === longestLine) return line;
|
||||
|
||||
const splitLine = line.split(' |');
|
||||
const splitLine = line.split(`${POLL_BAR_CHAR} `);
|
||||
const spaces = ' '.repeat(longestLine - line.length);
|
||||
return `${splitLine[0]} ${spaces}|${splitLine[1]}`;
|
||||
return `${splitLine[0]} ${spaces} ${splitLine[1]}`;
|
||||
}).join('\n');
|
||||
|
||||
// Text measurement estimation
|
||||
|
Loading…
Reference in New Issue
Block a user