Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update charts tooltips config + add missing chart labels translations #4734

Merged
merged 1 commit into from
Jun 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions frontend/src/components/projectDetail/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,14 @@ export default defineMessages({
id: 'projects.link.stats',
defaultMessage: 'More statistics',
},
mappedTasks: {
id: 'projects.stats.mapped',
defaultMessage: 'Mapped tasks',
},
validatedTasks: {
id: 'projects.stats.validated',
defaultMessage: 'Validated tasks',
},
shareMessage: {
id: 'project.share.twitter',
defaultMessage: 'Contribute mapping the project #{id} on {site}',
Expand Down
22 changes: 18 additions & 4 deletions frontend/src/components/projectDetail/timeline.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,33 @@
import React from 'react';
import { Line } from 'react-chartjs-2';
import { useIntl } from 'react-intl';

import messages from './messages';
import { formatTimelineData, formatTimelineTooltip } from '../../utils/formatChartJSData';
import { CHART_COLOURS } from '../../config';
import { useTimeDiff } from '../../hooks/UseTimeDiff';

export default function ProjectTimeline({ tasksByDay }: Object) {
const intl = useIntl();
const unit = useTimeDiff(tasksByDay);
const mappedTasksConfig = {
color: CHART_COLOURS.orange,
label: intl.formatMessage(messages.mappedTasks),
};
const validatedTasksConfig = {
color: CHART_COLOURS.red,
label: intl.formatMessage(messages.validatedTasks),
};

return (
<Line
data={formatTimelineData(tasksByDay, CHART_COLOURS.orange, CHART_COLOURS.red)}
data={formatTimelineData(tasksByDay, mappedTasksConfig, validatedTasksConfig)}
options={{
plugins: { legend: { position: 'top', align: 'end', labels: { boxWidth: 12 } } },
tooltips: {
callbacks: { label: (tooltip, data) => formatTimelineTooltip(tooltip, data, true) },
plugins: {
legend: { position: 'top', align: 'end', labels: { boxWidth: 12 } },
tooltip: {
callbacks: { label: (context) => formatTimelineTooltip(context, true) },
},
},
scales: { xAxes: [{ type: 'time', time: { unit: unit } }] },
}}
Expand Down
12 changes: 8 additions & 4 deletions frontend/src/components/projectStats/contributorsStats.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,10 @@ export default function ContributorsStats({ contributors }) {
<Bar
data={formatChartData(userExperienceReference, stats)}
options={{
plugins: { legend: { display: false } },
tooltips: { callbacks: { label: (tooltip, data) => formatTooltip(tooltip, data) } },
plugins: {
legend: { display: false },
tooltip: { callbacks: { label: (context) => formatTooltip(context) } },
},
}}
/>
</div>
Expand All @@ -110,8 +112,10 @@ export default function ContributorsStats({ contributors }) {
data={formatChartData(userLevelsReference, stats)}
options={{
aspectRatio: 2,
plugins: { legend: { position: 'right', labels: { boxWidth: 12 } } },
tooltips: { callbacks: { label: (tooltip, data) => formatTooltip(tooltip, data) } },
plugins: {
legend: { position: 'right', labels: { boxWidth: 12 } },
tooltip: { callbacks: { label: (context) => formatTooltip(context) } },
},
}}
/>
</div>
Expand Down
6 changes: 4 additions & 2 deletions frontend/src/components/projectStats/taskStatus.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,10 @@ const TasksByStatus = ({ stats }) => {
data={data}
options={{
aspectRatio: 2,
plugins: { legend: { position: 'right', labels: { boxWidth: 12 } } },
tooltips: { callbacks: { label: (tooltip, data) => formatTooltip(tooltip, data) } },
plugins: {
legend: { position: 'right', labels: { boxWidth: 12 } },
tooltip: { callbacks: { label: (context) => formatTooltip(context) } },
},
}}
/>
</div>
Expand Down
22 changes: 18 additions & 4 deletions frontend/src/components/teamsAndOrgs/tasksStatsChart.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
import React from 'react';
import { Bar } from 'react-chartjs-2';
import { useIntl } from 'react-intl';

import messages from '../projectDetail/messages';
import { CHART_COLOURS } from '../../config';
import { useTimeDiff } from '../../hooks/UseTimeDiff';
import { formatTasksStatsData, formatTimelineTooltip } from '../../utils/formatChartJSData';

const TasksStatsChart = ({ stats }) => {
const intl = useIntl();
const unit = useTimeDiff(stats);

const mappedTasksConfig = {
color: CHART_COLOURS.orange,
label: intl.formatMessage(messages.mappedTasks),
};
const validatedTasksConfig = {
color: CHART_COLOURS.red,
label: intl.formatMessage(messages.validatedTasks),
};
const options = {
plugins: { legend: { position: 'top', align: 'end', labels: { boxWidth: 12 } } },
tooltips: {
callbacks: { label: (tooltip, data) => formatTimelineTooltip(tooltip, data, false) },
plugins: {
legend: { position: 'top', align: 'end', labels: { boxWidth: 12 } },
tooltip: {
callbacks: { label: (context) => formatTimelineTooltip(context, false) },
},
},
scales: {
yAxes: [
Expand All @@ -32,7 +46,7 @@ const TasksStatsChart = ({ stats }) => {
};
return (
<Bar
data={formatTasksStatsData(stats, CHART_COLOURS.orange, CHART_COLOURS.red)}
data={formatTasksStatsData(stats, mappedTasksConfig, validatedTasksConfig)}
options={options}
/>
);
Expand Down
6 changes: 4 additions & 2 deletions frontend/src/components/userDetail/editsByNumbers.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,10 @@ const EditsByNumbers = ({ osmStats }) => {
data={data}
options={{
aspectRatio: 2,
plugins: { legend: { position: 'right', labels: { boxWidth: 12 } } },
tooltips: { callbacks: { label: (tooltip, data) => formatTooltip(tooltip, data) } },
plugins: {
legend: { position: 'right', labels: { boxWidth: 12 } },
tooltip: { callbacks: { label: (context) => formatTooltip(context) } },
},
}}
/>
) : (
Expand Down
6 changes: 4 additions & 2 deletions frontend/src/components/userDetail/topCauses.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,10 @@ const TopCauses = ({ userStats }) => {
data={data}
options={{
aspectRatio: 2,
plugins: { legend: { position: 'right', labels: { boxWidth: 12 } } },
tooltips: { callbacks: { label: (tooltip, data) => formatTooltip(tooltip, data) } },
plugins: {
legend: { position: 'right', labels: { boxWidth: 12 } },
tooltip: { callbacks: { label: (context) => formatTooltip(context) } },
},
}}
/>
) : (
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,8 @@
"projects.data.download.aoi": "Download AOI",
"projects.data.download.taskGrid": "Download Tasks Grid",
"projects.link.stats": "More statistics",
"projects.stats.mapped": "Mapped tasks",
"projects.stats.validated": "Validated tasks",
"project.share.twitter": "Contribute mapping the project #{id} on {site}",
"project.share.facebook": "Post on Facebook",
"project.share.linkedin": "Share on LinkedIn",
Expand Down
38 changes: 19 additions & 19 deletions frontend/src/utils/formatChartJSData.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,20 @@ export const formatChartData = (reference, stats) => {
return data;
};

export const formatTimelineData = (stats, mappedColour, validatedColour) => {
export const formatTimelineData = (stats, mappedTasksConfig, validatedTasksConfig) => {
let mapped = {
data: [],
backgroundColor: mappedColour,
borderColor: mappedColour,
backgroundColor: mappedTasksConfig.color,
borderColor: mappedTasksConfig.color,
fill: false,
label: 'Mapped tasks',
label: mappedTasksConfig.label,
};
let validated = {
data: [],
backgroundColor: validatedColour,
borderColor: validatedColour,
backgroundColor: validatedTasksConfig.color,
borderColor: validatedTasksConfig.color,
fill: false,
label: 'Validated tasks',
label: validatedTasksConfig.label,
};

const labels = stats.map((entry) => entry.date);
Expand All @@ -38,16 +38,16 @@ export const formatTimelineData = (stats, mappedColour, validatedColour) => {
return { datasets: [validated, mapped], labels: labels };
};

export const formatTasksStatsData = (stats, mappedColour, validatedColour) => {
export const formatTasksStatsData = (stats, mappedTasksConfig, validatedTasksConfig) => {
let mapped = {
data: [],
backgroundColor: mappedColour,
label: 'Mapped tasks',
backgroundColor: mappedTasksConfig.color,
label: mappedTasksConfig.label,
};
let validated = {
data: [],
backgroundColor: validatedColour,
label: 'Validated tasks',
backgroundColor: validatedTasksConfig.color,
label: validatedTasksConfig.label,
};

const labels = stats.map((entry) => entry.date);
Expand All @@ -57,18 +57,18 @@ export const formatTasksStatsData = (stats, mappedColour, validatedColour) => {
return { datasets: [mapped, validated], labels: labels };
};

export const formatTooltip = (tooltipItem, data) => {
var label = data.labels[tooltipItem.index] || '';
export const formatTooltip = (context) => {
var label = context.label;
if (label) label += ': ';
label += data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
label += context.dataset.data[context.dataIndex];

return (label += '%');
return `${label}%`;
};

export const formatTimelineTooltip = (tooltipItem, data, isPercent) => {
var label = data.datasets[tooltipItem.datasetIndex].label || '';
export const formatTimelineTooltip = (context, isPercent) => {
var label = context.dataset.label || '';
if (label) label += ': ';
label += data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
label += context.dataset.data[context.dataIndex];

return `${label}${isPercent ? '%' : ''}`;
};
72 changes: 42 additions & 30 deletions frontend/src/utils/tests/formatChartJSData.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,13 @@ describe('formatChartData', () => {

describe('formatTimelineData', () => {
it('return the correct information about the datasets', () => {
expect(formatTimelineData(projectContributionsByDay.stats, '#fff', '#092')).toEqual({
expect(
formatTimelineData(
projectContributionsByDay.stats,
{ color: '#fff', label: 'Mapped tasks' },
{ color: '#092', label: 'Validated tasks' },
),
).toEqual({
datasets: [
{
data: [0, 6, 19],
Expand All @@ -74,16 +80,6 @@ describe('formatTimelineData', () => {
});

describe('formatTimelineTooltip', () => {
const tooltipItem = {
xLabel: '2020-06-26',
yLabel: 18,
label: '2020-06-26',
value: '18',
index: 2,
datasetIndex: 1,
x: 1074.8309643713924,
y: 78.45394354462593,
};
const data = {
datasets: [
{
Expand All @@ -103,37 +99,41 @@ describe('formatTimelineTooltip', () => {
],
labels: ['2020-05-19', '2020-06-01', '2020-06-26'],
};
const tooltipItem = {
xLabel: '2020-06-26',
yLabel: 18,
label: 'Mapped tasks',
value: '18',
dataIndex: 2,
datasetIndex: 1,
x: 1074.8309643713924,
y: 78.45394354462593,
dataset: data.datasets[1],
};
it('returns correct information for Mapped tasks', () => {
expect(formatTimelineTooltip(tooltipItem, data, true)).toBe('Mapped tasks: 31%');
expect(formatTimelineTooltip(tooltipItem, data)).toBe('Mapped tasks: 31');
expect(formatTimelineTooltip(tooltipItem, true)).toBe('Mapped tasks: 31%');
expect(formatTimelineTooltip(tooltipItem, false)).toBe('Mapped tasks: 31');
expect(formatTimelineTooltip(tooltipItem)).toBe('Mapped tasks: 31');
});
it('returns correct information for Validated tasks', () => {
const tooltipItem2 = {
xLabel: '2020-06-26',
yLabel: 18,
label: '2020-06-26',
value: '18',
index: 0,
dataIndex: 0,
datasetIndex: 0,
x: 1074.8309643713924,
y: 78.45394354462593,
dataset: data.datasets[0],
};
expect(formatTimelineTooltip(tooltipItem2, data, true)).toBe('Validated tasks: 0%');
expect(formatTimelineTooltip(tooltipItem2, data)).toBe('Validated tasks: 0');
expect(formatTimelineTooltip(tooltipItem2, true)).toBe('Validated tasks: 0%');
expect(formatTimelineTooltip(tooltipItem2, false)).toBe('Validated tasks: 0');
expect(formatTimelineTooltip(tooltipItem2)).toBe('Validated tasks: 0');
});
});

describe('formatTooltip', () => {
const tooltipItem = {
xLabel: '',
yLabel: '',
label: '',
value: '',
index: 1,
datasetIndex: 0,
x: 173.3499984741211,
y: 124,
};
const data = {
datasets: [
{
Expand All @@ -148,20 +148,32 @@ describe('formatTooltip', () => {
],
labels: ['Building', 'Roads', 'Points of interests', 'Waterways'],
};
const tooltipItem = {
xLabel: '',
yLabel: '',
label: 'Roads',
value: '',
dataIndex: 1,
datasetIndex: 0,
x: 173.3499984741211,
y: 124,
dataset: data.datasets[0],
};
it('returns correct text with 30 percent', () => {
expect(formatTooltip(tooltipItem, data)).toBe('Roads: 30%');
expect(formatTooltip(tooltipItem)).toBe('Roads: 30%');
});
it('returns correct text with 42 percent', () => {
const tooltipItem = {
xLabel: '',
yLabel: '',
label: '',
label: 'Waterways',
value: '',
index: 3,
dataIndex: 3,
datasetIndex: 0,
x: 173.3499984741211,
y: 124,
dataset: data.datasets[0],
};
expect(formatTooltip(tooltipItem, data)).toBe('Waterways: 42%');
expect(formatTooltip(tooltipItem)).toBe('Waterways: 42%');
});
});