Skip to content

Commit

Permalink
Merge pull request #1018 from JGreenlee/dashboard-rewrite
Browse files Browse the repository at this point in the history
📊 Rewrite of the New Dashboard Tab
  • Loading branch information
shankari authored Sep 26, 2023
2 parents e93059f + bb4fdd0 commit 87b3456
Show file tree
Hide file tree
Showing 30 changed files with 1,763 additions and 1,953 deletions.
2 changes: 0 additions & 2 deletions package.cordovabuild.json
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@
"angular": "1.6.7",
"angular-animate": "1.6.7",
"angular-local-storage": "^0.7.1",
"angular-nvd3": "^1.0.7",
"angular-sanitize": "1.6.7",
"angular-simple-logger": "^0.1.7",
"angular-translate": "^2.18.1",
Expand Down Expand Up @@ -158,7 +157,6 @@
"moment-timezone": "^0.5.43",
"ng-i18next": "^1.0.7",
"npm": "^9.6.3",
"nvd3": "^1.8.6",
"phonegap-plugin-barcodescanner": "git+https://github.com/phonegap/phonegap-plugin-barcodescanner#v8.1.0",
"prop-types": "^15.8.1",
"react": "^18.2.*",
Expand Down
2 changes: 0 additions & 2 deletions package.serve.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@
"angular": "1.6.7",
"angular-animate": "1.6.7",
"angular-local-storage": "^0.7.1",
"angular-nvd3": "^1.0.7",
"angular-sanitize": "1.6.7",
"angular-simple-logger": "^0.1.7",
"angular-translate": "^2.18.1",
Expand Down Expand Up @@ -83,7 +82,6 @@
"moment-timezone": "^0.5.43",
"ng-i18next": "^1.0.7",
"npm": "^9.6.3",
"nvd3": "^1.8.6",
"prop-types": "^15.8.1",
"react": "^18.2.*",
"react-chartjs-2": "^5.2.0",
Expand Down
12 changes: 0 additions & 12 deletions www/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@
max-height: 50px;
}

/* nvd3 styles */
@import 'nvd3/build/nv.d3.css';

.fill-container {
display: block;
position: relative;
Expand Down Expand Up @@ -746,15 +743,6 @@ timestamp-badge[light-bg] {
padding: 5% 10%;
}

svg {
display: block;
}
#chart, #chart svg {
margin-right: 10px;
}
.nvd3, nv-noData {
font-weight: 300 !important;
}
.metric-datepicker {
/*height: 33px;*/
display: flex; /* establish flex container */
Expand Down
49 changes: 26 additions & 23 deletions www/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,11 @@
"less-than": " less than ",
"less": " less ",
"week-before": "vs. week before",
"this-week": "this week",
"pick-a-date": "Pick a date",
"trips": "trips",
"hours": "hours",
"minutes": "minutes",
"custom": "Custom"
},

Expand Down Expand Up @@ -142,42 +144,43 @@
"no-travel-hint": "To see more, change the filters above or go record some travel!"
},

"user-gender": "Gender",
"gender-male": "Male",
"gender-female": "Female",
"user-height": "Height",
"user-weight": "Weight",
"user-age": "Age",

"main-metrics":{
"dashboard": "Dashboard",
"summary": "My Summary",
"chart": "Chart",
"change-data": "Change dates:",
"distance": "My Distance",
"trips": "My Trips",
"duration": "My Duration",
"distance": "Distance",
"trips": "Trips",
"duration": "Duration",
"fav-mode": "My Favorite Mode",
"speed": "My Speed",
"footprint": "My Footprint",
"estimated-emissions": "Estimated CO₂ emissions",
"how-it-compares": "Ballpark comparisons",
"optimal": "Optimal (perfect mode choice for all my trips):",
"average": "Average for group:",
"avoided": "CO₂ avoided (vs. all 'taxi'):",
"optimal": "Optimal (perfect mode choice for all my trips)",
"average": "Group Avg.",
"worst-case": "Worse Case",
"label-to-squish": "Label trips to collapse the range into a single number",
"range-uncertain-footnote": "²Due to the uncertainty of unlabeled trips, estimates may fall anywhere within the shown range. Label more trips for richer estimates.",
"lastweek": "My last week value:",
"us-2030-goal": "US 2030 Goal Estimate:",
"us-2050-goal": "US 2050 Goal Estimate:",
"calories": "My Calories",
"calibrate": "Calibrate",
"us-2030-goal": "2030 Guideline¹",
"us-2050-goal": "2050 Guideline¹",
"us-goals-footnote": "¹Guidelines based on US decarbonization goals, scaled to per-capita travel-related emissions.",
"past-week" : "Past Week",
"prev-week" : "Prev. Week",
"no-summary-data": "No summary data",
"mean-speed": "My Average Speed",
"equals-cookies_one": "Equals at least {{count}} homemade chocolate chip cookie",
"equals-cookies_other": "Equals at least {{count}} homemade chocolate chip cookies",
"equals-icecream_one": "Equals at least {{count}} half cup vanilla ice cream",
"equals-icecream_other": "Equals at least {{count}} half cups vanilla ice cream",
"equals-bananas_one": "Equals at least {{count}} banana",
"equals-bananas_other": "Equals at least {{count}} bananas"
"user-totals": "My Totals",
"group-totals": "Group Totals",
"active-minutes": "Active Minutes",
"weekly-active-minutes": "Weekly minutes of active travel",
"daily-active-minutes": "Daily minutes of active travel",
"active-minutes-table": "Table of active minutes metrics",
"weekly-goal": "Weekly Goal³",
"weekly-goal-footnote": "³Weekly goal based on CDC recommendation of 150 minutes of moderate activity per week.",
"labeled": "Labeled",
"unlabeled": "Unlabeled²",
"footprint-label": "Footprint (kg CO₂)"
},

"main-inf-scroll" : {
Expand Down
1 change: 0 additions & 1 deletion www/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ import './js/survey/enketo/infinite_scroll_filters.js';
import './js/survey/enketo/enketo-trip-button.js';
import './js/survey/enketo/enketo-demographics.js';
import './js/survey/enketo/enketo-add-note-button.js';
import './js/metrics.js';
import './js/control/general-settings.js';
import './js/control/emailService.js';
import './js/control/uploadService.js';
Expand Down
3 changes: 2 additions & 1 deletion www/js/appTheme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ const AppTheme = {
level4: '#e0f0ff', // lch(94% 50 250)
level5: '#d6ebff', // lch(92% 50 250)
},
success: '#38872e', // lch(50% 55 135)
success: '#00a665', // lch(60% 55 155)
warn: '#f8cf53', //lch(85% 65 85)
danger: '#f23934' // lch(55% 85 35)
},
roundness: 5,
Expand Down
206 changes: 16 additions & 190 deletions www/js/components/BarChart.tsx
Original file line number Diff line number Diff line change
@@ -1,201 +1,27 @@
import React from "react";
import Chart, { Props as ChartProps } from "./Chart";
import { useTheme } from "react-native-paper";
import { getGradient } from "./charting";

import React, { useRef, useState } from 'react';
import { array, string, bool } from 'prop-types';
import { angularize } from '../angular-react-helper';
import { View } from 'react-native';
import { useTheme } from 'react-native-paper';
import { Chart, CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend, TimeScale } from 'chart.js';
import { Bar } from 'react-chartjs-2';
import Annotation, { AnnotationOptions } from 'chartjs-plugin-annotation';

Chart.register(
CategoryScale,
LinearScale,
TimeScale,
BarElement,
Title,
Tooltip,
Legend,
Annotation,
);

const BarChart = ({ chartData, axisTitle, lineAnnotations=null, isHorizontal=false }) => {
type Props = Omit<ChartProps, 'type'> & {
meter?: {high: number, middle: number, dash_key: string},
}
const BarChart = ({ meter, ...rest }: Props) => {

const { colors } = useTheme();
const [ numVisibleDatasets, setNumVisibleDatasets ] = useState(1);

const barChartRef = useRef<Chart>(null);

const defaultPalette = [
'#c95465', // red oklch(60% 0.15 14)
'#4a71b1', // blue oklch(55% 0.11 260)
'#d2824e', // orange oklch(68% 0.12 52)
'#856b5d', // brown oklch(55% 0.04 50)
'#59894f', // green oklch(58% 0.1 140)
'#e0cc55', // yellow oklch(84% 0.14 100)
'#b273ac', // purple oklch(64% 0.11 330)
'#f09da6', // pink oklch(78% 0.1 12)
'#b3aca8', // grey oklch(75% 0.01 55)
'#80afad', // teal oklch(72% 0.05 192)
]

const indexAxis = isHorizontal ? 'y' : 'x';

function getChartHeight() {
/* when horizontal charts have more data, they should get taller
so they don't look squished */
if (isHorizontal) {
// 'ideal' chart height is based on the number of datasets and number of unique index values
const uniqueIndexVals = [];
chartData.forEach(e => e.records.forEach(r => {
if (!uniqueIndexVals.includes(r[indexAxis])) uniqueIndexVals.push(r[indexAxis]);
}));
const numIndexVals = uniqueIndexVals.length;
const idealChartHeight = numVisibleDatasets * numIndexVals * 8;

/* each index val should be at least 20px tall for visibility,
and the graph itself should be at least 250px tall */
const minChartHeight = Math.max(numIndexVals * 20, 250);

// return whichever is greater
return { height: Math.max(idealChartHeight, minChartHeight) };
if (meter) {
rest.getColorForChartEl = (chart, dataset, ctx, colorFor) => {
const darkenDegree = colorFor == 'border' ? 0.25 : 0;
const alpha = colorFor == 'border' ? 1 : 0;
return getGradient(chart, meter, dataset, ctx, alpha, darkenDegree);
}
// vertical charts will just match the parent container
return { height: '100%' };
rest.borderWidth = 3;
}

return (
<View style={[getChartHeight(), {padding: 12}]}>
<Bar ref={barChartRef}
data={{
datasets: chartData.map((d, i) => ({
label: d.label,
data: d.records,
// cycle through the default palette, repeat if necessary
backgroundColor: defaultPalette[i % defaultPalette.length],
}))
}}
options={{
indexAxis: indexAxis,
responsive: true,
maintainAspectRatio: false,
resizeDelay: 1,
scales: {
...(isHorizontal ? {
y: {
offset: true,
type: 'time',
adapters: {
date: { zone: 'utc' },
},
time: {
unit: 'day',
tooltipFormat: 'DDD', // Luxon "localized date with full month": e.g. August 6, 2014
},
beforeUpdate: (axis) => {
setNumVisibleDatasets(axis.chart.getVisibleDatasetCount())
},
reverse: true,
},
x: {
title: { display: true, text: axisTitle },
},
} : {
x: {
offset: true,
type: 'time',
adapters: {
date: { zone: 'utc' },
},
time: {
unit: 'day',
tooltipFormat: 'DDD', // Luxon "localized date with full month": e.g. August 6, 2014
},
},
y: {
title: { display: true, text: axisTitle },
},
}),
},
plugins: {
...(lineAnnotations?.length > 0 && {
annotation: {
annotations: lineAnnotations.map((a, i) => ({
type: 'line',
label: {
display: true,
padding: { x: 3, y: 1 },
borderRadius: 0,
backgroundColor: 'rgba(0,0,0,.7)',
color: 'rgba(255,255,255,1)',
font: { size: 10 },
position: 'start',
content: a.label,
},
...(isHorizontal ? { xMin: a.value, xMax: a.value }
: { yMin: a.value, yMax: a.value }),
borderColor: colors.onBackground,
borderWidth: 2,
borderDash: [3, 3],
} satisfies AnnotationOptions)),
}
}),
}
}} />
</View>
)
<Chart type="bar" {...rest} />
);
}

BarChart.propTypes = {
chartData: array,
axisTitle: string,
lineAnnotations: array,
isHorizontal: bool,
};

angularize(BarChart, 'BarChart', 'emission.main.barchart');
export default BarChart;

// const sampleAnnotations = [
// { value: 35, label: 'Target1' },
// { value: 65, label: 'Target2' },
// ];

// const sampleChartData = [
// {
// label: 'Primary',
// records: [
// { x: moment('2023-06-20'), y: 20 },
// { x: moment('2023-06-21'), y: 30 },
// { x: moment('2023-06-23'), y: 80 },
// { x: moment('2023-06-24'), y: 40 },
// ],
// },
// {
// label: 'Secondary',
// records: [
// { x: moment('2023-06-21'), y: 10 },
// { x: moment('2023-06-22'), y: 50 },
// { x: moment('2023-06-23'), y: 30 },
// { x: moment('2023-06-25'), y: 40 },
// ],
// },
// {
// label: 'Tertiary',
// records: [
// { x: moment('2023-06-20'), y: 30 },
// { x: moment('2023-06-22'), y: 40 },
// { x: moment('2023-06-24'), y: 10 },
// { x: moment('2023-06-25'), y: 60 },
// ],
// },
// {
// label: 'Quaternary',
// records: [
// { x: moment('2023-06-22'), y: 10 },
// { x: moment('2023-06-23'), y: 20 },
// { x: moment('2023-06-24'), y: 30 },
// { x: moment('2023-06-25'), y: 40 },
// ],
// },
// ];
Loading

0 comments on commit 87b3456

Please sign in to comment.