├── public
├── favicon.ico
├── project.png
├── favicons
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ ├── favicon-96x96.png
│ ├── ms-icon-144x144.png
│ ├── apple-icon-114x114.png
│ ├── apple-icon-120x120.png
│ ├── apple-icon-144x144.png
│ ├── apple-icon-152x152.png
│ ├── apple-icon-180x180.png
│ ├── apple-icon-57x57.png
│ ├── apple-icon-60x60.png
│ ├── apple-icon-72x72.png
│ ├── apple-icon-76x76.png
│ ├── android-icon-192x192.png
│ └── manifest.json
└── index.html
├── src
├── settings
│ ├── tanyofish-tweeted-on-cha-2018.json
│ ├── tanyoung-piano_practice-2019.json
│ ├── tanyoung-piano_practice-2020.json
│ ├── tanyofish-swimming-2016.json
│ ├── tanyofish-tweeted-on-tvxq-2018.json
│ ├── plabinu-swimming-2016.json
│ ├── plabinu-swimming-2017.json
│ ├── tanyofish-swimming-2017.json
│ ├── tanyofish-twitter-2018.json
│ ├── tanyofish-twitter-2019.json
│ ├── tanyofish-twitter-2020.json
│ ├── tanyofish-twitter-2013.json
│ ├── tanyofish-twitter-2014.json
│ ├── tanyofish-twitter-2015.json
│ ├── tanyofish-twitter-2016.json
│ ├── tanyofish-twitter-2017.json
│ ├── tanyoung-steps-2018.json
│ ├── tanyoung-steps-2019.json
│ ├── tanyoung-steps-2020.json
│ ├── tanyoung-steps-2021.json
│ ├── tanyoung-steps-2022.json
│ ├── tanyoung-steps-2023.json
│ ├── mr._moon-driving-2018.json
│ ├── tanyoung-flights-climbed-2018.json
│ ├── tanyoung-flights-climbed-2019.json
│ ├── tanyoung-flights-climbed-2020.json
│ ├── tanyoung-flights-climbed-2021.json
│ ├── tanyoung-flights-climbed-2022.json
│ ├── tanyoung-flights-climbed-2023.json
│ ├── tanyofish-swimming-2018.json
│ ├── tanyoung-time-at-cafe-2016.json
│ ├── tanykim-reactions-on-facebook-2018.json
│ ├── tanyoung-time-at-marty_s-2016.json
│ ├── tanyofish-swimming-2019.json
│ ├── tanyofish-swimming-2022.json
│ ├── tanyofish-swimming-2023.json
│ ├── tanykim-time-at-dr._lancaster-2018.json
│ ├── tanykim-time-at-dr._lancaster-2019.json
│ ├── tanykim-time-at-dr._lancaster-2020.json
│ ├── tanyofish-swimming-2020.json
│ ├── dr._lancaster-electricity-usage-2018.json
│ ├── dr._lancaster-electricity-usage-2019.json
│ ├── dr._lancaster-electricity-usage-2020.json
│ ├── tanyofish-swimming-2021.json
│ └── datasets.json
├── index.js
├── components
│ ├── vis
│ │ ├── DayTexts.js
│ │ ├── Legend.js
│ │ ├── MonthPaths.js
│ │ ├── Lines.js
│ │ ├── ToolTip.js
│ │ ├── BarChart.js
│ │ └── Blocks.js
│ ├── Summary.js
│ ├── Menu.js
│ ├── Max.js
│ ├── ByDay.js
│ ├── Stats.js
│ ├── Calendar.js
│ └── Main.js
├── less
│ ├── Visualization.less
│ └── colors.less
├── processors
│ ├── dimensions.js
│ ├── colors.js
│ ├── formats.js
│ └── analysis.js
├── data
│ ├── tanyofish-tweeted-on-cha-2018.json
│ ├── tanyofish-tweeted-on-tvxq-2018.json
│ ├── tanyofish-swimming-2017.json
│ ├── plabinu-swimming-2017.json
│ ├── tanyoung-time-at-cafe-2016.json
│ ├── tanyoung-piano_practice-2020.json
│ ├── tanyofish-swimming-2020.json
│ ├── tanyofish-swimming-2018.json
│ ├── tanyoung-piano_practice-2019.json
│ ├── tanyofish-swimming-2022.json
│ ├── tanyofish-swimming-2019.json
│ ├── tanyofish-swimming-2016.json
│ ├── tanyofish-swimming-2021.json
│ ├── plabinu-swimming-2016.json
│ └── tanyofish-swimming-2023.json
├── App.js
├── index.less
└── index.css
├── .gitignore
├── package.json
└── README.md
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tanykim/quantify-your-year/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/public/project.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tanykim/quantify-your-year/HEAD/public/project.png
--------------------------------------------------------------------------------
/public/favicons/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tanykim/quantify-your-year/HEAD/public/favicons/favicon-16x16.png
--------------------------------------------------------------------------------
/public/favicons/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tanykim/quantify-your-year/HEAD/public/favicons/favicon-32x32.png
--------------------------------------------------------------------------------
/public/favicons/favicon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tanykim/quantify-your-year/HEAD/public/favicons/favicon-96x96.png
--------------------------------------------------------------------------------
/public/favicons/ms-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tanykim/quantify-your-year/HEAD/public/favicons/ms-icon-144x144.png
--------------------------------------------------------------------------------
/public/favicons/apple-icon-114x114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tanykim/quantify-your-year/HEAD/public/favicons/apple-icon-114x114.png
--------------------------------------------------------------------------------
/public/favicons/apple-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tanykim/quantify-your-year/HEAD/public/favicons/apple-icon-120x120.png
--------------------------------------------------------------------------------
/public/favicons/apple-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tanykim/quantify-your-year/HEAD/public/favicons/apple-icon-144x144.png
--------------------------------------------------------------------------------
/public/favicons/apple-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tanykim/quantify-your-year/HEAD/public/favicons/apple-icon-152x152.png
--------------------------------------------------------------------------------
/public/favicons/apple-icon-180x180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tanykim/quantify-your-year/HEAD/public/favicons/apple-icon-180x180.png
--------------------------------------------------------------------------------
/public/favicons/apple-icon-57x57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tanykim/quantify-your-year/HEAD/public/favicons/apple-icon-57x57.png
--------------------------------------------------------------------------------
/public/favicons/apple-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tanykim/quantify-your-year/HEAD/public/favicons/apple-icon-60x60.png
--------------------------------------------------------------------------------
/public/favicons/apple-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tanykim/quantify-your-year/HEAD/public/favicons/apple-icon-72x72.png
--------------------------------------------------------------------------------
/public/favicons/apple-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tanykim/quantify-your-year/HEAD/public/favicons/apple-icon-76x76.png
--------------------------------------------------------------------------------
/public/favicons/android-icon-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tanykim/quantify-your-year/HEAD/public/favicons/android-icon-192x192.png
--------------------------------------------------------------------------------
/src/settings/tanyofish-tweeted-on-cha-2018.json:
--------------------------------------------------------------------------------
1 | {
2 | "year": 2018,
3 | "author": "tanyofish",
4 | "gender": "female",
5 | "topic": "tweeted about Cha",
6 | "pastVerb": "tweeted",
7 | "type": "count",
8 | "metric": "tweet",
9 | "considerFrequency": true
10 | }
--------------------------------------------------------------------------------
/src/settings/tanyoung-piano_practice-2019.json:
--------------------------------------------------------------------------------
1 | {
2 | "year":2019,
3 | "author":"tanyoung",
4 | "topic":"piano_practice",
5 | "gender":"female",
6 | "pastVerb":"played the piano",
7 | "type":"duration",
8 | "metric":"minute",
9 | "considerFrequency":true
10 | }
--------------------------------------------------------------------------------
/src/settings/tanyoung-piano_practice-2020.json:
--------------------------------------------------------------------------------
1 | {
2 | "year":2020,
3 | "author":"tanyoung",
4 | "topic":"piano_practice",
5 | "gender":"female",
6 | "pastVerb":"played the piano",
7 | "type":"duration",
8 | "metric":"minute",
9 | "considerFrequency":true
10 | }
--------------------------------------------------------------------------------
/src/settings/tanyofish-swimming-2016.json:
--------------------------------------------------------------------------------
1 | {
2 | "year": 2016,
3 | "author": "tanyofish",
4 | "gender": "female",
5 | "topic": "swimming",
6 | "pastVerb": "swam",
7 | "type": "distance",
8 | "metric": "yard",
9 | "abbr": "yd",
10 | "considerFrequency": true
11 | }
--------------------------------------------------------------------------------
/src/settings/tanyofish-tweeted-on-tvxq-2018.json:
--------------------------------------------------------------------------------
1 | {
2 | "year": 2018,
3 | "author": "tanyofish",
4 | "gender": "female",
5 | "topic": "tweeted about TVXQ!/U-Know/Max",
6 | "pastVerb": "tweeted",
7 | "type": "count",
8 | "metric": "tweet",
9 | "considerFrequency": true
10 | }
--------------------------------------------------------------------------------
/src/settings/plabinu-swimming-2016.json:
--------------------------------------------------------------------------------
1 | {
2 | "year": 2016,
3 | "author": "plabinu",
4 | "gender": "female",
5 | "topic": "swimming",
6 | "pastVerb": "swam",
7 | "type": "distance",
8 | "metric": "meter",
9 | "abbr": "m",
10 | "considerFrequency": true,
11 | "color": "purple"
12 | }
--------------------------------------------------------------------------------
/src/settings/plabinu-swimming-2017.json:
--------------------------------------------------------------------------------
1 | {
2 | "year": 2017,
3 | "author": "plabinu",
4 | "gender": "female",
5 | "topic": "swimming",
6 | "pastVerb": "swam",
7 | "type": "distance",
8 | "metric": "meter",
9 | "abbr": "m",
10 | "considerFrequency": true,
11 | "color": "purple"
12 | }
--------------------------------------------------------------------------------
/src/settings/tanyofish-swimming-2017.json:
--------------------------------------------------------------------------------
1 | {
2 | "year": 2017,
3 | "author": "tanyofish",
4 | "gender": "female",
5 | "topic": "swimming",
6 | "pastVerb": "swam",
7 | "type": "distance",
8 | "metric": "yard",
9 | "abbr": "yd",
10 | "considerFrequency": true,
11 | "color": "purple"
12 | }
--------------------------------------------------------------------------------
/src/settings/tanyofish-twitter-2018.json:
--------------------------------------------------------------------------------
1 | {
2 | "year":2018,
3 | "author":"tanyofish",
4 | "topic":"twitter",
5 | "gender":"female",
6 | "pastVerb":"tweeted",
7 | "type":"count",
8 | "metric":"tweet",
9 | "dataSource":{
10 | "name":"Twitter",
11 | "url":"http://www.twitter.com/"
12 | },
13 | "considerFrequency":false
14 | }
--------------------------------------------------------------------------------
/src/settings/tanyofish-twitter-2019.json:
--------------------------------------------------------------------------------
1 | {
2 | "year":2019,
3 | "author":"tanyofish",
4 | "topic":"twitter",
5 | "gender":"female",
6 | "pastVerb":"tweeted",
7 | "type":"count",
8 | "metric":"tweet",
9 | "dataSource":{
10 | "name":"Twitter",
11 | "url":"http://www.twitter.com/"
12 | },
13 | "considerFrequency":false
14 | }
--------------------------------------------------------------------------------
/src/settings/tanyofish-twitter-2020.json:
--------------------------------------------------------------------------------
1 | {
2 | "year":2020,
3 | "author":"tanyofish",
4 | "topic":"twitter",
5 | "gender":"female",
6 | "pastVerb":"tweeted",
7 | "type":"count",
8 | "metric":"tweet",
9 | "dataSource":{
10 | "name":"Twitter",
11 | "url":"http://www.twitter.com/"
12 | },
13 | "considerFrequency":false
14 | }
--------------------------------------------------------------------------------
/src/settings/tanyofish-twitter-2013.json:
--------------------------------------------------------------------------------
1 | {
2 | "year": 2013,
3 | "author": "tanyofish",
4 | "gender": "female",
5 | "topic": "twitter",
6 | "pastVerb": "tweeted",
7 | "type": "count",
8 | "metric": "tweet",
9 | "dataSource": {
10 | "name": "Twitter",
11 | "url": "http://www.twitter.com/"
12 | },
13 | "considerFrequency": false
14 | }
--------------------------------------------------------------------------------
/src/settings/tanyofish-twitter-2014.json:
--------------------------------------------------------------------------------
1 | {
2 | "year": 2014,
3 | "author": "tanyofish",
4 | "gender": "female",
5 | "topic": "twitter",
6 | "pastVerb": "tweeted",
7 | "type": "count",
8 | "metric": "tweet",
9 | "dataSource": {
10 | "name": "Twitter",
11 | "url": "http://www.twitter.com/"
12 | },
13 | "considerFrequency": false
14 | }
--------------------------------------------------------------------------------
/src/settings/tanyofish-twitter-2015.json:
--------------------------------------------------------------------------------
1 | {
2 | "year": 2015,
3 | "author": "tanyofish",
4 | "gender": "female",
5 | "topic": "twitter",
6 | "pastVerb": "tweeted",
7 | "type": "count",
8 | "metric": "tweet",
9 | "dataSource": {
10 | "name": "Twitter",
11 | "url": "http://www.twitter.com/"
12 | },
13 | "considerFrequency": false
14 | }
--------------------------------------------------------------------------------
/src/settings/tanyofish-twitter-2016.json:
--------------------------------------------------------------------------------
1 | {
2 | "year": 2016,
3 | "author": "tanyofish",
4 | "gender": "female",
5 | "topic": "twitter",
6 | "pastVerb": "tweeted",
7 | "type": "count",
8 | "metric": "tweet",
9 | "dataSource": {
10 | "name": "Twitter",
11 | "url": "http://www.twitter.com/"
12 | },
13 | "considerFrequency": false
14 | }
--------------------------------------------------------------------------------
/src/settings/tanyofish-twitter-2017.json:
--------------------------------------------------------------------------------
1 | {
2 | "year": 2017,
3 | "author": "tanyofish",
4 | "gender": "female",
5 | "topic": "twitter",
6 | "pastVerb": "tweeted",
7 | "type": "count",
8 | "metric": "tweet",
9 | "dataSource": {
10 | "name": "Twitter",
11 | "url": "http://www.twitter.com/"
12 | },
13 | "considerFrequency": false
14 | }
--------------------------------------------------------------------------------
/src/settings/tanyoung-steps-2018.json:
--------------------------------------------------------------------------------
1 | {
2 | "year":2018,
3 | "author":"tanyoung",
4 | "topic":"steps",
5 | "gender":"female",
6 | "pastVerb":"walked",
7 | "type":"count",
8 | "metric":"step",
9 | "dataSource":{
10 | "name":"Apple iOS Health",
11 | "url":"https://www.apple.com/ios/health/"
12 | },
13 | "considerFrequency":false
14 | }
--------------------------------------------------------------------------------
/src/settings/tanyoung-steps-2019.json:
--------------------------------------------------------------------------------
1 | {
2 | "year":2019,
3 | "author":"tanyoung",
4 | "topic":"steps",
5 | "gender":"female",
6 | "pastVerb":"walked",
7 | "type":"count",
8 | "metric":"step",
9 | "dataSource":{
10 | "name":"Apple iOS Health",
11 | "url":"https://www.apple.com/ios/health/"
12 | },
13 | "considerFrequency":false
14 | }
--------------------------------------------------------------------------------
/src/settings/tanyoung-steps-2020.json:
--------------------------------------------------------------------------------
1 | {
2 | "year":2020,
3 | "author":"tanyoung",
4 | "topic":"steps",
5 | "gender":"female",
6 | "pastVerb":"walked",
7 | "type":"count",
8 | "metric":"step",
9 | "dataSource":{
10 | "name":"Apple iOS Health",
11 | "url":"https://www.apple.com/ios/health/"
12 | },
13 | "considerFrequency":false
14 | }
--------------------------------------------------------------------------------
/src/settings/tanyoung-steps-2021.json:
--------------------------------------------------------------------------------
1 | {
2 | "year":2021,
3 | "author":"tanyoung",
4 | "topic":"steps",
5 | "gender":"female",
6 | "pastVerb":"walked",
7 | "type":"count",
8 | "metric":"step",
9 | "dataSource":{
10 | "name":"Apple iOS Health",
11 | "url":"https://www.apple.com/ios/health/"
12 | },
13 | "considerFrequency":false
14 | }
--------------------------------------------------------------------------------
/src/settings/tanyoung-steps-2022.json:
--------------------------------------------------------------------------------
1 | {
2 | "year":2022,
3 | "author":"tanyoung",
4 | "topic":"steps",
5 | "gender":"female",
6 | "pastVerb":"walked",
7 | "type":"count",
8 | "metric":"step",
9 | "dataSource":{
10 | "name":"Apple iOS Health",
11 | "url":"https://www.apple.com/ios/health/"
12 | },
13 | "considerFrequency":false
14 | }
--------------------------------------------------------------------------------
/src/settings/tanyoung-steps-2023.json:
--------------------------------------------------------------------------------
1 | {
2 | "year":2023,
3 | "author":"tanyoung",
4 | "topic":"steps",
5 | "gender":"female",
6 | "pastVerb":"walked",
7 | "type":"count",
8 | "metric":"step",
9 | "dataSource":{
10 | "name":"Apple iOS Health",
11 | "url":"https://www.apple.com/ios/health/"
12 | },
13 | "considerFrequency":false
14 | }
--------------------------------------------------------------------------------
/src/settings/mr._moon-driving-2018.json:
--------------------------------------------------------------------------------
1 | {
2 | "year":2018,
3 | "author":"mr._moon",
4 | "topic":"driving",
5 | "gender":"male",
6 | "pastVerb":"drove",
7 | "type":"distance",
8 | "metric":"mile",
9 | "dataSource":{
10 | "name":"Metromile",
11 | "url":"https://www.metromile.com/"
12 | },
13 | "decimal":2,
14 | "considerFrequency":true
15 | }
--------------------------------------------------------------------------------
/src/settings/tanyoung-flights-climbed-2018.json:
--------------------------------------------------------------------------------
1 | {
2 | "year":2018,
3 | "author":"tanyoung",
4 | "topic":"flights climbed",
5 | "gender":"female",
6 | "pastVerb":"climbed",
7 | "type":"count",
8 | "metric":"floor",
9 | "dataSource":{
10 | "name":"Apple iOS Health",
11 | "url":"https://www.apple.com/ios/health/"
12 | },
13 | "considerFrequency":false
14 | }
--------------------------------------------------------------------------------
/src/settings/tanyoung-flights-climbed-2019.json:
--------------------------------------------------------------------------------
1 | {
2 | "year":2019,
3 | "author":"tanyoung",
4 | "topic":"flights climbed",
5 | "gender":"female",
6 | "pastVerb":"climbed",
7 | "type":"count",
8 | "metric":"floor",
9 | "dataSource":{
10 | "name":"Apple iOS Health",
11 | "url":"https://www.apple.com/ios/health/"
12 | },
13 | "considerFrequency":false
14 | }
--------------------------------------------------------------------------------
/src/settings/tanyoung-flights-climbed-2020.json:
--------------------------------------------------------------------------------
1 | {
2 | "year":2020,
3 | "author":"tanyoung",
4 | "topic":"flights climbed",
5 | "gender":"female",
6 | "pastVerb":"climbed",
7 | "type":"count",
8 | "metric":"floor",
9 | "dataSource":{
10 | "name":"Apple iOS Health",
11 | "url":"https://www.apple.com/ios/health/"
12 | },
13 | "considerFrequency":false
14 | }
--------------------------------------------------------------------------------
/src/settings/tanyoung-flights-climbed-2021.json:
--------------------------------------------------------------------------------
1 | {
2 | "year":2021,
3 | "author":"tanyoung",
4 | "topic":"flights climbed",
5 | "gender":"female",
6 | "pastVerb":"climbed",
7 | "type":"count",
8 | "metric":"floor",
9 | "dataSource":{
10 | "name":"Apple iOS Health",
11 | "url":"https://www.apple.com/ios/health/"
12 | },
13 | "considerFrequency":false
14 | }
--------------------------------------------------------------------------------
/src/settings/tanyoung-flights-climbed-2022.json:
--------------------------------------------------------------------------------
1 | {
2 | "year":2022,
3 | "author":"tanyoung",
4 | "topic":"flights climbed",
5 | "gender":"female",
6 | "pastVerb":"climbed",
7 | "type":"count",
8 | "metric":"floor",
9 | "dataSource":{
10 | "name":"Apple iOS Health",
11 | "url":"https://www.apple.com/ios/health/"
12 | },
13 | "considerFrequency":false
14 | }
--------------------------------------------------------------------------------
/src/settings/tanyoung-flights-climbed-2023.json:
--------------------------------------------------------------------------------
1 | {
2 | "year":2023,
3 | "author":"tanyoung",
4 | "topic":"flights climbed",
5 | "gender":"female",
6 | "pastVerb":"climbed",
7 | "type":"count",
8 | "metric":"floor",
9 | "dataSource":{
10 | "name":"Apple iOS Health",
11 | "url":"https://www.apple.com/ios/health/"
12 | },
13 | "considerFrequency":false
14 | }
--------------------------------------------------------------------------------
/src/settings/tanyofish-swimming-2018.json:
--------------------------------------------------------------------------------
1 | {
2 | "year": 2018,
3 | "author": "tanyofish",
4 | "gender": "female",
5 | "topic": "swimming",
6 | "pastVerb": "swam",
7 | "type": "distance",
8 | "metric": "yard",
9 | "alt_unit": "meter",
10 | "conversion": 1.09361,
11 | "abbr": "yd",
12 | "alt_abbr": "m",
13 | "considerFrequency": true,
14 | "color": "purple"
15 | }
--------------------------------------------------------------------------------
/src/settings/tanyoung-time-at-cafe-2016.json:
--------------------------------------------------------------------------------
1 | {
2 | "year": 2016,
3 | "author": "tanyoung",
4 | "gender": "female",
5 | "topic": "time at Cafe",
6 | "pastVerb": "spent time at cafes",
7 | "type": "duration",
8 | "metric": "minute",
9 | "dataSource": {
10 | "name": "Moves App",
11 | "url": "http://moves-app.com/"
12 | },
13 | "considerFrequency": true
14 | }
--------------------------------------------------------------------------------
/src/settings/tanykim-reactions-on-facebook-2018.json:
--------------------------------------------------------------------------------
1 | {
2 | "year":2018,
3 | "author":"tanykim",
4 | "topic":"reactions on facebook",
5 | "gender":"female",
6 | "pastVerb":"reacted on Facebook",
7 | "type":"count",
8 | "metric":"reaction",
9 | "dataSource":{
10 | "name":"Facebook",
11 | "url":"https://www.facebook.com/"
12 | },
13 | "considerFrequency":false
14 | }
--------------------------------------------------------------------------------
/src/settings/tanyoung-time-at-marty_s-2016.json:
--------------------------------------------------------------------------------
1 | {
2 | "year": 2016,
3 | "author": "tanyoung",
4 | "gender": "female",
5 | "topic": "time at Marty's",
6 | "pastVerb": "spent time at Marty's",
7 | "type": "duration",
8 | "metric": "minute",
9 | "dataSource": {
10 | "name": "Moves App",
11 | "url": "http://moves-app.com/"
12 | },
13 | "considerFrequency": true
14 | }
--------------------------------------------------------------------------------
/src/settings/tanyofish-swimming-2019.json:
--------------------------------------------------------------------------------
1 | {
2 | "year": 2019,
3 | "author": "tanyofish",
4 | "gender": "female",
5 | "topic": "swimming at pool",
6 | "pastVerb": "swam",
7 | "type": "distance",
8 | "metric": "yard",
9 | "alt_unit": "meter",
10 | "conversion": 1.09361,
11 | "abbr": "yd",
12 | "alt_abbr": "m",
13 | "considerFrequency": true,
14 | "color": "purple"
15 | }
16 |
--------------------------------------------------------------------------------
/src/settings/tanyofish-swimming-2022.json:
--------------------------------------------------------------------------------
1 | {
2 | "year": 2022,
3 | "author": "tanyofish",
4 | "gender": "female",
5 | "topic": "swimming",
6 | "pastVerb": "swam",
7 | "type": "distance",
8 | "metric": "yard",
9 | "alt_unit": "meter",
10 | "conversion": 1.09361,
11 | "abbr": "yd",
12 | "alt_abbr": "m",
13 | "considerFrequency": true,
14 | "color": "purple"
15 | }
--------------------------------------------------------------------------------
/src/settings/tanyofish-swimming-2023.json:
--------------------------------------------------------------------------------
1 | {
2 | "year": 2023,
3 | "author": "tanyofish",
4 | "gender": "female",
5 | "topic": "swimming",
6 | "pastVerb": "swam",
7 | "type": "distance",
8 | "metric": "yard",
9 | "alt_unit": "meter",
10 | "conversion": 1.09361,
11 | "abbr": "yd",
12 | "alt_abbr": "m",
13 | "considerFrequency": true,
14 | "color": "purple"
15 | }
--------------------------------------------------------------------------------
/src/settings/tanykim-time-at-dr._lancaster-2018.json:
--------------------------------------------------------------------------------
1 | {
2 | "year":2018,
3 | "author":"tanykim",
4 | "topic":"time at dr._lancaster",
5 | "gender":"female",
6 | "pastVerb":"stayed at home",
7 | "type":"duration",
8 | "metric":"hour",
9 | "dataSource":{
10 | "name":"Google Maps",
11 | "url":"https://www.google.com/maps/timeline"
12 | },
13 | "considerFrequency":false,
14 | "decimal":1
15 | }
--------------------------------------------------------------------------------
/src/settings/tanykim-time-at-dr._lancaster-2019.json:
--------------------------------------------------------------------------------
1 | {
2 | "year":2019,
3 | "author":"tanykim",
4 | "topic":"time at dr._lancaster",
5 | "gender":"female",
6 | "pastVerb":"stayed at home",
7 | "type":"duration",
8 | "metric":"hour",
9 | "dataSource":{
10 | "name":"Google Maps",
11 | "url":"https://www.google.com/maps/timeline"
12 | },
13 | "considerFrequency":false,
14 | "decimal":1
15 | }
--------------------------------------------------------------------------------
/src/settings/tanykim-time-at-dr._lancaster-2020.json:
--------------------------------------------------------------------------------
1 | {
2 | "year":2020,
3 | "author":"tanykim",
4 | "topic":"time at dr._lancaster",
5 | "gender":"female",
6 | "pastVerb":"stayed at home",
7 | "type":"duration",
8 | "metric":"hour",
9 | "dataSource":{
10 | "name":"Google Maps",
11 | "url":"https://www.google.com/maps/timeline"
12 | },
13 | "considerFrequency":false,
14 | "decimal":1
15 | }
--------------------------------------------------------------------------------
/src/settings/tanyofish-swimming-2020.json:
--------------------------------------------------------------------------------
1 | {
2 | "year": 2020,
3 | "author": "tanyofish",
4 | "gender": "female",
5 | "topic": "swimming at pool",
6 | "pastVerb": "swam",
7 | "type": "distance",
8 | "metric": "yard",
9 | "alt_unit": "meter",
10 | "conversion": 1.09361,
11 | "abbr": "yd",
12 | "alt_abbr": "m",
13 | "considerFrequency": true,
14 | "color": "purple"
15 | }
--------------------------------------------------------------------------------
/src/settings/dr._lancaster-electricity-usage-2018.json:
--------------------------------------------------------------------------------
1 | {
2 | "year":2018,
3 | "author":"dr._lancaster",
4 | "topic":"electricity usage",
5 | "gender":"female",
6 | "pastVerb":"used electricity",
7 | "type":"usage",
8 | "metric":"kWh",
9 | "dataSource":{
10 | "name":"PG&E",
11 | "url":"https://www.pge.com/"
12 | },
13 | "decimal":2,
14 | "hasNegative":true,
15 | "isReverse":true,
16 | "considerFrequency":false
17 | }
--------------------------------------------------------------------------------
/src/settings/dr._lancaster-electricity-usage-2019.json:
--------------------------------------------------------------------------------
1 | {
2 | "year":2019,
3 | "author":"dr._lancaster",
4 | "topic":"electricity usage",
5 | "gender":"female",
6 | "pastVerb":"used electricity",
7 | "type":"usage",
8 | "metric":"kWh",
9 | "dataSource":{
10 | "name":"PG&E",
11 | "url":"https://www.pge.com/"
12 | },
13 | "decimal":2,
14 | "hasNegative":true,
15 | "isReverse":true,
16 | "considerFrequency":false
17 | }
--------------------------------------------------------------------------------
/src/settings/dr._lancaster-electricity-usage-2020.json:
--------------------------------------------------------------------------------
1 | {
2 | "year":2020,
3 | "author":"dr._lancaster",
4 | "topic":"electricity usage",
5 | "gender":"female",
6 | "pastVerb":"used electricity",
7 | "type":"usage",
8 | "metric":"kWh",
9 | "dataSource":{
10 | "name":"PG&E",
11 | "url":"https://www.pge.com/"
12 | },
13 | "decimal":2,
14 | "hasNegative":true,
15 | "isReverse":true,
16 | "considerFrequency":false
17 | }
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { Router, Route, hashHistory } from 'react-router';
4 | import App from './App';
5 | import 'bootstrap-css-only/css/bootstrap.min.css';
6 | import './index.css';
7 |
8 | ReactDOM.render(
9 |
10 |
11 |
12 | ,
13 | document.getElementById('root')
14 | );
15 |
--------------------------------------------------------------------------------
/src/settings/tanyofish-swimming-2021.json:
--------------------------------------------------------------------------------
1 | {
2 | "year": 2021,
3 | "author": "tanyofish",
4 | "gender": "female",
5 | "topic": "swimming",
6 | "pastVerb": "swam",
7 | "type": "distance",
8 | "metric": "yard",
9 | "alt_unit": "meter",
10 | "conversion": 1.09361,
11 | "abbr": "yd",
12 | "alt_abbr": "m",
13 | "considerFrequency": true,
14 | "color": "purple",
15 | "dataSource": {
16 | "name": "Apple Health"
17 | }
18 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # testing
7 | coverage
8 |
9 | # production
10 | build
11 |
12 | # misc
13 | .DS_Store
14 | .env
15 | npm-debug.log
16 |
17 | package-lock.json
18 |
19 | src/data/*.json
20 | src/settings/*.json
21 | !src/settings/datasets.json
22 | !src/*/tanyofish-*.json
23 | !src/*/tanykim*.json
24 | !src/*/tanyoung*.json
25 | !src/*/dr.*.json
26 | !src/*/mr.*.json
27 |
28 |
--------------------------------------------------------------------------------
/src/components/vis/DayTexts.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import moment from 'moment';
3 |
4 | class DayTexts extends Component {
5 | render() {
6 | const text = [...Array(7).keys()].map((day) =>
7 | (
13 | {moment().startOf('week').add(day, 'day').format('ddd')}
14 | )
15 | );
16 |
17 | return (
18 |
19 | {text}
20 |
21 | );
22 | }
23 | }
24 |
25 | export default DayTexts;
26 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "activity-log",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "bootstrap-css-only": "^3.3.7",
7 | "chroma-js": "^1.3.5",
8 | "d3": "^4.12.2",
9 | "less": "^4.1.1",
10 | "moment": "^2.20.1",
11 | "react": "^15.6.2",
12 | "react-dom": "^15.6.2",
13 | "react-fa": "^4.2.0",
14 | "react-render-html": "^0.1.6",
15 | "react-router": "^3.2.0",
16 | "react-scripts": "^1.0.17"
17 | },
18 | "scripts": {
19 | "start": "react-scripts start",
20 | "build": "react-scripts build",
21 | "test": "react-scripts test --env=jsdom",
22 | "eject": "react-scripts eject"
23 | },
24 | "homepage": "https://projects.tany.kim/quantify-your-year"
25 | }
--------------------------------------------------------------------------------
/public/favicons/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "App",
3 | "icons": [
4 | {
5 | "src": "\/android-icon-36x36.png",
6 | "sizes": "36x36",
7 | "type": "image\/png",
8 | "density": "0.75"
9 | },
10 | {
11 | "src": "\/android-icon-48x48.png",
12 | "sizes": "48x48",
13 | "type": "image\/png",
14 | "density": "1.0"
15 | },
16 | {
17 | "src": "\/android-icon-72x72.png",
18 | "sizes": "72x72",
19 | "type": "image\/png",
20 | "density": "1.5"
21 | },
22 | {
23 | "src": "\/android-icon-96x96.png",
24 | "sizes": "96x96",
25 | "type": "image\/png",
26 | "density": "2.0"
27 | },
28 | {
29 | "src": "\/android-icon-144x144.png",
30 | "sizes": "144x144",
31 | "type": "image\/png",
32 | "density": "3.0"
33 | },
34 | {
35 | "src": "\/android-icon-192x192.png",
36 | "sizes": "192x192",
37 | "type": "image\/png",
38 | "density": "4.0"
39 | }
40 | ]
41 | }
--------------------------------------------------------------------------------
/src/components/vis/Legend.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {prefix} from './../../processors/formats';
3 |
4 | class Legend extends Component {
5 | render() {
6 | const {brewer, containerW, rectW, marginRight, steps} = this.props;
7 | const maxRectW = (containerW - marginRight * 2) / (steps.length - 1);
8 | const width = Math.min(maxRectW, rectW * 2);
9 | const height = rectW;
10 |
11 | const blocks = [...Array(steps.length - 1).keys()].map((i) =>
12 | (
)
16 | );
17 |
18 | const labels = steps.map((step, i) =>
19 | (
20 | {prefix(step)}
21 |
)
22 | );
23 |
24 | return (
25 |
26 |
{blocks}
27 |
{labels}
28 |
29 | );
30 | }
31 | }
32 |
33 | export default Legend;
34 |
--------------------------------------------------------------------------------
/src/less/Visualization.less:
--------------------------------------------------------------------------------
1 | text {
2 | -webkit-user-select: none; /* Chrome all / Safari all */
3 | -moz-user-select: none; /* Firefox all */
4 | -ms-user-select: none; /* IE 10+ */
5 | user-select: none;
6 | cursor: default;
7 | }
8 | .block {
9 | &:hover {
10 | stroke: @main;
11 | stroke-width: 1px;
12 | };
13 | }
14 | .lines {
15 | stroke: #ced4da;
16 | }
17 | .month-path {
18 | stroke: @main;
19 | stroke-width: 1.5px;
20 | shape-rendering: crispEdges;
21 | fill: none;
22 | }
23 | .month-text {
24 | font-size: 14px;
25 | alignment-baseline: hanging;
26 | }
27 | .day-text {
28 | font-size: 14px;
29 | alignment-baseline: central;
30 | text-anchor: end;
31 | }
32 | .label-text {
33 | font-size: 14px;
34 | alignment-baseline: central;
35 | }
36 |
37 | .axis path {
38 | stroke: none;
39 | }
40 | .tick {
41 | line {
42 | stroke: fade(@main, 20%);
43 | }
44 | text {
45 | font-size: 12px;
46 | }
47 | }
48 |
49 | .bg {
50 | fill: @main;
51 | }
52 | .tp {
53 | font-weight: normal;
54 | font-size: 14px;
55 | fill: #FFF;
56 | }
--------------------------------------------------------------------------------
/src/components/vis/MonthPaths.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import moment from 'moment';
3 | import {getPoints, getPath} from './../../processors/dimensions';
4 |
5 | class MonthPaths extends Component {
6 | render() {
7 | const {rectW, h, margin, year} = this.props;
8 |
9 | const path = [...Array(12).keys()].map(month =>
10 |
14 | );
15 |
16 | const text = [...Array(12).keys()].map(month => {
17 | const p = getPoints(rectW, h, margin, year, month);
18 | return (
19 |
25 | {moment(month + 1, 'M').format('MMM')}
26 |
27 | );
28 | });
29 |
30 | return (
31 |
32 | {path}
33 | {text}
34 |
35 | );
36 | }
37 | }
38 |
39 | export default MonthPaths;
--------------------------------------------------------------------------------
/src/components/vis/Lines.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class HorizontalLines extends Component {
4 | render() {
5 | const {startDay, endDay, margin, rectW} = this.props;
6 | const w = rectW;
7 | const lines = [...Array(8).keys()].map(day =>
8 | day ? w : 0}
10 | x2={this.props.w - (endDay + 1 < day ? w : 0)}
11 | y1={day * w}
12 | y2={day * w}
13 | key={day}
14 | />
15 | );
16 | return (
17 | {lines}
18 | );
19 | }
20 | }
21 |
22 | class VerticalLines extends Component {
23 | render() {
24 | const {noOfWeeks, startDay, endDay, h, margin, rectW} = this.props;
25 | const w = rectW;
26 | const lines = [...Array(noOfWeeks + 1).keys()].map((week) =>
27 | ()
34 | );
35 | return (
36 | {lines}
37 | );
38 | }
39 | }
40 |
41 | export { HorizontalLines, VerticalLines };
--------------------------------------------------------------------------------
/src/components/Summary.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { getSum, getAverages } from './../processors/analysis';
3 | import { pronoun, capitalize, pluralize } from './../processors/formats';
4 | import { getColorForTwoDirection } from './../processors/colors';
5 |
6 | class Summary extends Component {
7 | render() {
8 | let { data, author, pastVerb, year, type, metric, considerFrequency, gender, abbr, color, hasNegative, isReverse } = this.props;
9 | const sum = getSum(data);
10 | const averages = getAverages(sum, data.length, year);
11 | if (hasNegative) {
12 | color = getColorForTwoDirection(sum < 0 && isReverse || !isReverse && sum >= 0);
13 | }
14 | return (
15 |
16 |
17 | {capitalize(author)} {pastVerb}
18 | {type === 'duration' ? ` for ` : ` total `}
19 | {pluralize(sum, metric)}:
20 | {` `}in average {pluralize(averages.day, metric)}
21 | {` `}per {considerFrequency ? ` an active` : `a`} day.
22 |
23 | {` `}Over the whole year, {pronoun(gender, false)} {pastVerb}
24 | {` `}{averages.week}{abbr}/week, and
25 | {` `}{averages.month}{abbr}/month.
26 |
27 |
28 | );
29 | }
30 | }
31 |
32 | export default Summary;
33 |
--------------------------------------------------------------------------------
/src/components/Menu.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Link } from 'react-router';
3 | import { Icon } from 'react-fa';
4 | import Dataset from './../settings/datasets.json';
5 | import {capitalize, spacize} from './../processors/formats';
6 |
7 | class Menu extends Component {
8 | constructor(props) {
9 | super(props);
10 | this.hideMenu = this.hideMenu.bind(this);
11 | }
12 |
13 | hideMenu() {
14 | this.props.close(true);
15 | }
16 |
17 | render() {
18 | const list = Dataset.map((d, i) => {
19 | const elms = d.data.map((elm, j) => {
20 | let url = `${elm.author.split(' ').join('_')}-${elm.topic.replace(/ /g, '-')}-${d.year}`;
21 | url = url.toLowerCase();
22 | return (
23 |
24 | {capitalize(spacize(elm.author)) + '\'s ' + capitalize(elm.topic)}
25 |
26 | )
27 | });
28 | return (
29 |
33 | )
34 | })
35 | return (
36 |
37 |
Close
38 |
{list}
39 |
40 | )
41 | }
42 | }
43 |
44 | export default Menu;
45 |
--------------------------------------------------------------------------------
/src/components/Max.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { capitalize, pluralize } from './../processors/formats';
3 | import { getColorForTwoDirection } from './../processors/colors';
4 |
5 | class Max extends Component {
6 | render() {
7 | let { unit, calendar, author, type, color, metric, hasNegative, isReverse } = this.props;
8 | const max = calendar.max[unit];
9 | const maxActiveList = max.list.map((item, i) => {
10 | let display = item;
11 | const count = max.list.length;
12 | // when there are only two items, space after the first.
13 | if (i === 0 && count === 2) {
14 | display += ' ';
15 | // Oxford comma
16 | } else if (i >= 0 && i < count - 1) {
17 | display += ', ';
18 | }
19 | // before the last item
20 | if (i >= 0 && i === count - 2) {
21 | display += 'and ';
22 | }
23 | let tail = '.';
24 | if (i === count - 1 && count > 5) {
25 | tail = ` (total ${count}).`
26 | }
27 | return ({display}{i === count - 1 ? tail : ''});
28 | });
29 | const conj = { day: 'on', week: 'during', month: 'in' };
30 | if (hasNegative) {
31 | color = getColorForTwoDirection(max.val < 0 && isReverse || !isReverse && max.val >= 0);
32 | }
33 | return (
34 |
35 | { capitalize(author) }'s record {type} in a {unit} is
36 | { ` ` } {pluralize(max.val, metric)}:
37 | { ` ` } achieved { conj[unit] } {maxActiveList}
38 |
39 | );
40 | }
41 | }
42 |
43 | export default Max;
44 |
--------------------------------------------------------------------------------
/src/components/ByDay.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import BarChart from './vis/BarChart';
3 | import {capitalize} from './../processors/formats';
4 |
5 | class ByDay extends Component {
6 | constructor(props) {
7 | super(props);
8 | this.state = {
9 | selection: 'value'
10 | };
11 | this.onChange = this.onChange.bind(this);
12 | }
13 |
14 | onChange(e) {
15 | this.setState({selection: e.target.value});
16 | }
17 |
18 | render() {
19 | const {topic, considerFrequency, metric, type, data, color, dims} = this.props;
20 |
21 | return (
22 |
23 |
24 | See the {capitalize(topic)} Data by Day {!considerFrequency && ` (total ${type} in ${metric})`}
25 |
26 |
38 |
39 |
40 |
41 |
42 | );
43 | }
44 | }
45 |
46 | export default ByDay;
--------------------------------------------------------------------------------
/src/components/Stats.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import renderHTML from 'react-render-html';
3 | import { pronoun, pluralize } from './../processors/formats';
4 | import { getStatsByUnit } from './../processors/analysis';
5 |
6 | class Stats extends Component {
7 | render() {
8 | const { unit, data, year, gender, pastVerb, color, topic } = this.props;
9 | const stats = getStatsByUnit(data, year);
10 |
11 | const unitSentence = `${pronoun(gender, true)} ${pastVerb}
12 | ${pluralize(stats.active[unit], unit, stats.total[unit])} in ${year}. `;
13 |
14 | const consec = stats.consec[unit];
15 | const consecActiveList = consec.active.list.map((item, i) =>
16 | {item}{i < consec.active.list.length - 1 && ', '}
17 | );
18 | const consecInactiveList = consec.inactive.list.map((item, i) =>
19 | {item}{i < consec.inactive.list.length - 1 && ', '}
20 | );
21 |
22 | return (
23 |
24 | {renderHTML(unitSentence)}
25 | {unit === 'day' &&
26 | This means in average
27 | {` `}{(stats.active[unit] / 52).toFixed(1)} days/week
28 | {` `}and {(stats.active[unit] / 12).toFixed(1)} days/month.
29 |
30 | }
31 | {consec.active.count > 1 &&
Record for consecutive {unit}s of {topic} is
32 | {` `}{pluralize(consec.active.count, unit)}
33 |
34 | , happened {consec.active.list.length} time
35 | {consec.active.list.length > 1 ? 's: ' : ': '}
36 | {consecActiveList}.
37 |
}
38 | {consec.inactive.count > 1 &&
39 | Longest break was {pluralize(consec.inactive.count, unit)}:
40 | {` `}{consecInactiveList}.
41 |
}
42 |
43 | );
44 | }
45 | }
46 |
47 | export default Stats;
48 |
--------------------------------------------------------------------------------
/src/components/Calendar.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import Blocks from './vis/Blocks.js';
3 | import {HorizontalLines, VerticalLines} from './vis/Lines.js';
4 | import DayTexts from './vis/DayTexts.js';
5 | import MonthPaths from './vis/MonthPaths.js';
6 | import ToolTip from './vis/ToolTip.js';
7 | import {getCalendarInfo} from './../processors/dimensions';
8 |
9 | class Calendar extends Component {
10 | constructor(props) {
11 | super(props);
12 | this.rectHovered = this.rectHovered.bind(this);
13 | this.state = {isHovered: false};
14 | }
15 |
16 | rectHovered(isHovered, x, y, id, val, altVal) {
17 | this.setState({isHovered, x, y, id, val, altVal});
18 | }
19 |
20 | render() {
21 | const {data, year, brewer, unit, dims, calendar, abbr, altAbbr, decimal} = this.props;
22 | const calInfo = getCalendarInfo(year);
23 | const {rectW, w, h, margin} = dims;
24 | return (
25 |
26 |
57 |
58 | );
59 | }
60 | }
61 |
62 | export default Calendar;
--------------------------------------------------------------------------------
/src/components/vis/ToolTip.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import {humanizeUnitId, locale} from './../../processors/formats';
3 |
4 | class ToolTip extends Component {
5 |
6 | constructor(props) {
7 | super(props);
8 | this.state = {x: 0, y: 0, textX: 0, textY: 0, path: ''};
9 | }
10 |
11 | componentDidMount() {
12 | const {margin, unit, rectW, x, y, w} = this.props;
13 | const xPos = margin.left + x
14 | + (unit === 'day' && rectW / 2)
15 | + (unit === 'month' && rectW * 2);
16 | const yPos = margin.legend + margin.top + y + rectW / 3;
17 |
18 | //max value according to dim
19 | const cW = rectW / 3 * 2; //width of chevron
20 | const cH = rectW / 2; //height of chevron
21 | //tooltip width and height, excluding chevron dim
22 | let toolTipW = document.getElementById('tt-label').clientWidth + cW;
23 | let toolTipH = margin.legend + margin.top;
24 | const distToC = x * toolTipW / w;
25 |
26 | //cehvron end point, then cW up, then to the left, up, right, bottom, left, then close
27 | const path = `M 0 0 l -${cW / 2} -${cH}
28 | h ${-distToC}
29 | v ${-(toolTipH - cH)}
30 | h ${toolTipW + cW}
31 | v ${toolTipH - cH}
32 | h ${-(toolTipW - distToC)} Z`;
33 | const textX = -distToC + cW / 2;
34 | const textY = -(toolTipH - cH / 2);
35 | this.setState({x: xPos, y: yPos, textX, textY, path});
36 | }
37 |
38 | render() {
39 | let {year, unit, id, val, abbr, decimal, altVal, altAbbr} = this.props;
40 | year = unit === 'day' ? null : year;
41 | const {x, y, textX, textY, path} = this.state;
42 | return (
43 |
44 |
45 |
50 | {humanizeUnitId(year, unit, id)}
51 |
52 | {locale(val, decimal)}{abbr}
53 | {altVal != null && ` (${locale(altVal, decimal)}${altAbbr})`}
54 |
55 |
56 |
57 | );
58 | }
59 | }
60 |
61 | export default ToolTip;
--------------------------------------------------------------------------------
/src/less/colors.less:
--------------------------------------------------------------------------------
1 | @main: #212529;
2 | @sub: #ced4da;
3 |
4 | @blue: #F0FFFF, #87CEEB, SlateBlue, #031968;
5 | @red: lightyellow, orange, deeppink, darkred;
6 | @green: lightyellow, lightgreen, darkgreen;
7 | @teal: lightyellow, turquoise, Teal;
8 | @purple: lightyellow, coral, mediumvioletred, purple;
9 | @brown: lightyellow, LightSalmon, darkOrange, Brown;
10 |
11 | @two-red: #ffffbf, #fee090, #fc8d59, #d73027;
12 | @two-blue: #ffffbf, #e0f3f8, #91bfdb, #4575b4;
13 |
14 | .blue {
15 | .author, a { color: extract(@blue, 4); }
16 | i { background-color: extract(@blue, 4); }
17 | ii { background-color: extract(@blue, 2); }
18 | .text-highlight a { color: extract(@blue, 2) !important;}
19 | }
20 | .red {
21 | .author, a { color: extract(@red, 4); }
22 | i { background-color: extract(@red, 4); }
23 | ii { background-color: extract(@red, 2); }
24 | .text-highlight a { color: extract(@red, 2) !important; }
25 | }
26 | .green {
27 | .author, a { color: extract(@green, 3); }
28 | i { background-color: extract(@green, 3); }
29 | ii { background-color: extract(@green, 2); }
30 | .text-highlight a { color: extract(@green, 2) !important; }
31 | }
32 | .teal {
33 | .author, a { color: extract(@teal, 3); }
34 | i { background-color: extract(@teal, 3); }
35 | ii { background-color: extract(@teal, 2); }
36 | .text-highlight a { color: extract(@teal, 2) !important; }
37 | }
38 | .purple {
39 | .author, a { color: extract(@purple, 4); }
40 | i { background-color: extract(@purple, 4); }
41 | ii { background-color: extract(@purple, 2); }
42 | .text-highlight a { color: extract(@purple, 2) !important; }
43 | }
44 | .brown {
45 | .author, a { color: extract(@brown, 4); }
46 | i { background-color: extract(@brown, 4); }
47 | ii { background-color: extract(@brown, 3); }
48 | .text-highlight a { color: extract(@brown, 3) !important; }
49 | }
50 |
51 | .two-red {
52 | .author, a { color: extract(@two-red, 4); }
53 | i { background-color: extract(@two-red, 4); }
54 | ii { background-color: extract(@two-red, 3); }
55 | .text-highlight a { color: extract(@two-red, 3) !important; }
56 | }
57 |
58 | .two-blue {
59 | .author, a { color: extract(@two-blue, 4); }
60 | i { background-color: extract(@two-blue, 4); }
61 | ii { background-color: extract(@two-blue, 3); }
62 | .text-highlight a { color: extract(@two-blue, 3) !important; }
63 | }
--------------------------------------------------------------------------------
/src/processors/dimensions.js:
--------------------------------------------------------------------------------
1 | import moment from 'moment';
2 |
3 | const getCalendarInfo = (year) => {
4 | const startDate = moment(`${year}0101`, 'YYYYMMDD');
5 | const endDate = moment(`${year}1231`, 'YYYYMMDD');
6 | const startWeek = startDate.clone().startOf('week');
7 | const endWeek = endDate.clone().add(7, 'day').startOf('week');
8 | const noOfWeeks = endWeek.diff(startWeek, 'weeks');
9 |
10 | return {
11 | startDay: startDate.day(),
12 | endDay: endDate.day(),
13 | noOfWeeks,
14 | year,
15 | };
16 | }
17 |
18 | let containerW;
19 |
20 | const getVisDimensions = (year) => {
21 |
22 | const calendarInfo = getCalendarInfo(year);
23 | const {noOfWeeks} = calendarInfo;
24 |
25 | containerW = containerW || document.getElementById('width').clientWidth - 30;
26 |
27 | let margin = {
28 | legend: 20,
29 | top: 40,
30 | left: 60,
31 | bottom: 8
32 | };
33 |
34 | const rectW = Math.max(Math.floor((containerW - margin.left) / noOfWeeks), 20);
35 | margin.right = rectW;
36 | const w = rectW * noOfWeeks;
37 | margin.left = Math.max(40, containerW - w - margin.right);
38 |
39 | return {
40 | rectW,
41 | margin,
42 | containerW,
43 | w: noOfWeeks * rectW,
44 | h: rectW * 7,
45 | };
46 |
47 | }
48 |
49 | const getPoints = (rectW, h, margin, year, month, sd, sw) => {
50 | const startDay = sd != null ? sd : moment([year, month]).day();
51 | const startWeek = sw || moment([year, month]).week() - 1;
52 |
53 | const x = startWeek * rectW;
54 | const y = startDay * rectW;
55 |
56 | const sY = h + margin.bottom;
57 | const diff = startDay > 0 ? rectW : 0;
58 | const eY = -margin.top;
59 |
60 | return {x, y, sY, diff, eY, startDay, startWeek};
61 | }
62 |
63 | const getPath = (props, month) => {
64 | const p = getPoints(props.rectW, props.h, props.margin, props.year, month);
65 | return `M ${p.x}, ${p.sY} V ${p.y} h ${p.diff} V ${p.eY}`;
66 | }
67 |
68 | const getAreaPath = (rectW, h, margin, year, month) => {
69 | const sp = getPoints(rectW, h, margin, year, month);
70 | let np;
71 | if (+month < 11) {
72 | np = getPoints(rectW, h, margin, year, +month + 1);
73 | } else {
74 | // December has 31 days, 31 % 7 = 3
75 | const nysd = (sp.startDay + 3) % 7;
76 | // if the new year's first day is Sunday or Monday, diff should be rectW
77 | const nyw = sp.startWeek + (sp.startDay >= 4 ? 5 : 4);
78 | np = getPoints(rectW, h, margin, year, null, nysd, nyw);
79 | }
80 | return `M ${sp.x}, ${h} V ${sp.y} h ${sp.diff} V 0 H ${np.x} h ${np.diff} V ${np.y} h ${-np.diff} V ${h} Z`;
81 | }
82 |
83 | export { getCalendarInfo, getVisDimensions, getPoints, getPath, getAreaPath };
--------------------------------------------------------------------------------
/src/processors/colors.js:
--------------------------------------------------------------------------------
1 | import chroma from 'chroma-js';
2 |
3 | const colors = {
4 | blue: ['#F0FFFF', '#87CEEB', 'SlateBlue', '#031968'],
5 | red: ['lightyellow', 'orange', 'deeppink', 'darkred'],
6 | green: ['lightyellow', 'lightgreen', 'darkgreen'],
7 | teal: ['lightyellow', 'turquoise', 'Teal'],
8 | purple: ['lightyellow', 'coral', 'mediumvioletred', 'purple'],
9 | brown: ['lightyellow', 'LightSalmon', 'darkOrange', 'Brown']
10 | };
11 |
12 | const getColorForTwoDirection = (isReverse) => {
13 | return isReverse ? 'two-blue' : 'two-red';
14 | };
15 |
16 | const getRandomColor = () => {
17 | const themes = Object.keys(colors);
18 | const random = Math.floor(Math.random() * themes.length);
19 | return themes[random];
20 | }
21 |
22 | const getColorBrewer = (setting, color) => {
23 | const { steps, distance } = setting;
24 | const brewer = chroma.bezier(colors[color]).scale().domain(steps);
25 | return steps.map(step => brewer(step + distance / 2));
26 | }
27 |
28 | const getTwoColorsBrewer = (setting, isReverse) => {
29 | // from red to blue
30 | const { steps, distance, min, max } = setting;
31 | let colorScale = ['#d73027', '#f17d4e', '#febf7d', '#ffffbf', '#b5d0de', '#7ba2cc', '#2954b8'];
32 | if (isReverse) {
33 | // if positive number means negative meaning, reverse.
34 | colorScale.reverse();
35 | }
36 | const minNormalized = Math.abs(min) < Math.abs(max) ? -1 * max : min;
37 | const maxNormalized = Math.abs(min) > Math.abs(max) ? -1 * min : max;
38 | const brewer = chroma.scale(colorScale).domain([minNormalized, maxNormalized]);
39 | return steps.map(step => brewer(step + distance / 2));
40 | }
41 |
42 | const getBlockColor = (brewer, steps, value) => {
43 | // out of legend boundary
44 | let color;
45 | if (value > steps[steps.length - 1]) {
46 | color = 'black';
47 | } else if (value < steps[0]) {
48 | color = '#ced4da';
49 | } else {
50 | let index = 0;
51 | for (let i = 1; i < steps.length; i++) {
52 | if (value < steps[i]) {
53 | index = i - 1;
54 | break;
55 | }
56 | }
57 | color = brewer[index]
58 | }
59 | return color;
60 | }
61 |
62 | const twoColors = {
63 | 'two-red': '#d73027',
64 | 'two-blue': '#4575b4',
65 | };
66 |
67 | const getMaxColor = (c) => {
68 | // two directional charts, get the opposite color for the positive values
69 | if (c.slice(0, 3) === 'two') {
70 | return c === 'two-blue' ? twoColors['two-red'] : twoColors['two-blue'];
71 | } else {
72 | return colors[c][colors[c].length - 1];
73 | }
74 | }
75 |
76 | const getColorForNegative = (c) => {
77 | return twoColors[c];
78 | }
79 |
80 | export {
81 | colors,
82 | getColorForTwoDirection,
83 | getRandomColor,
84 | getColorBrewer,
85 | getTwoColorsBrewer,
86 | getBlockColor,
87 | getMaxColor,
88 | getColorForNegative,
89 | };
90 |
--------------------------------------------------------------------------------
/src/components/Main.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import Legend from './vis/Legend';
3 | import Calendar from './Calendar';
4 | import Max from './Max';
5 | import Stats from './Stats';
6 | import {getCalendar} from './../processors/analysis';
7 | import {capitalize} from './../processors/formats';
8 | import {getColorBrewer, getTwoColorsBrewer} from './../processors/colors';
9 | import {Icon} from 'react-fa';
10 |
11 |
12 | class Visualization extends Component {
13 | constructor(props) {
14 | super(props);
15 | this.onUnitChange = this.onUnitChange.bind(this);
16 | this.state = {unit: 'day'};
17 | }
18 |
19 | onUnitChange(e) {
20 | this.setState({unit: e.target.value});
21 | }
22 |
23 | render() {
24 | const {setting, data, dims} = this.props;
25 | const {year, color, abbr, alt_abbr, hasNegative, isReverse, decimal} = setting;
26 | const {unit} = this.state;
27 | const calendar = getCalendar(data, year, hasNegative, isReverse);
28 | const brewer = hasNegative ?
29 | getTwoColorsBrewer(calendar.range[unit], isReverse) :
30 | getColorBrewer(calendar.range[unit], color, hasNegative, isReverse);
31 |
32 | return (
33 |
34 |
35 | {['day', 'week', 'month'].map(u =>
36 |
42 | {capitalize(u)}
43 | )
44 | }
45 |
46 |
47 |
55 |
56 |
57 | Slide calender
58 |
59 |
70 |
74 | {setting.considerFrequency &&
75 |
80 | }
81 |
82 | );
83 | }
84 | }
85 |
86 | export default Visualization;
87 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | Quantify Your Year
43 |
44 |
45 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Quantify Your Year
2 | Calendar-based visualization of one kind of activity over the course of a calendar year
3 |
4 | ## URL and Datasets
5 | The URL would be ```your_project_address/#/[AUTHOR]-[ACTIVITY_TOPIC]-[YEAR]```.
6 | Name your setting and data files following the convention above (e.g., tanyoung-swimming-2016.json).
7 |
8 | Also update ```src/settings/datasets.json``` if you want to show this dataset in the selection menu on top of the page.
9 |
10 | ## Setting File Format
11 | The setting file contains following information. For example,
12 | ```
13 | {
14 | "year": 2016,
15 | "author": "Tanyoung",
16 | "gender": "female",
17 | "topic": "swimming",
18 | "pastVerb": "swam",
19 | "type": "distance",
20 | "considerFrequency": true,
21 | "metric": "yard",
22 | "abbr": "yd",
23 | "color": "blue",
24 | "alt_unit": "meter",
25 | "conversion": 1.09361,
26 | "alt_abbr": "m",
27 | "decimal": 1,
28 | "hasNegative": false,
29 | "isReverse": false,
30 | }
31 | ```
32 | * Gender: gender of the person, choose from female, male, and other
33 | * Past Verb: a past tense verb matching the activity topic
34 | * Type: Measurement of the activity, e.g., duration, distance, steps
35 | * Metric: Unit of the type, use singular form. e.g., minute, meter, step,
36 | * Abbribiation (optional): Same as metric if no abbreviation is common. e.g., m, yd, km
37 | * Consider Frequency: False if most of the days have data so the number of days with valid data does not give insights.
38 | * Color (optional): Choose the highlight color from blue, red, teal, green, purple. If not configured, one color is randomly selected.
39 | * Alternative Unit (optional): Specify an alternative unit if it exists.
40 | * Alternative Abbribiation (optional)
41 | * Decimal (optional): If the data values contain decimal number, specify.
42 | * Has Negative: If the data contains negative values, specify as true.
43 | * Is Reverse: If the data contains negative values, and the negative ones have positive meanings (e.g., production/consumtion of energy of solar panels)
44 |
45 | If the frequency matters (e.g., one may not swim every day), this project provides further analysis including consecutive days/week/month.
46 |
47 | Save this file as ```[AUTHOR]-[ACTIVITY_TOPIC]-[YEAR].json``` under ```src/settings```.
48 |
49 | ## Data File Format
50 | The data should be an array of dates with valid numbered data value. For example,
51 | ```
52 | [
53 | {
54 | "date": "1/2/2016",
55 | "value": 2600
56 | },
57 | {
58 | "date": "11/30/2016",
59 | "value": 2600
60 | }
61 | ]
62 | ```
63 | Save this file as ```[AUTHOR]-[ACTIVITY_TOPIC]-[YEAR].json``` under ```src/data```.
64 |
65 | If you log your data on Google Spreadsheet, try this convenient [converter](https://www.npmjs.com/package/google-spreadsheet-to-json).
66 |
67 | I wrote some Python scripts to generate both dataset and setting JSON files with downloadable data from Facebook, Twitter, Google Takeout, PG&E, iOS Health App, and Metromile. Check out [this repo](https://github.com/tanykim/quantify-your-year-data-generator).
68 |
69 | ## Development
70 | ```
71 | npm install
72 | npm start
73 | ```
74 |
75 | ## Build
76 | For production-ready files
77 | ```
78 | npm run build
79 | ```
80 |
81 | ## Made with React
82 | This project was bootstrapped with [Create React App](https://github.com/facebookincubator/create-react-app).
--------------------------------------------------------------------------------
/src/data/tanyofish-tweeted-on-cha-2018.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "date":"8/10/2018",
4 | "value":1
5 | },
6 | {
7 | "date":"8/26/2018",
8 | "value":1
9 | },
10 | {
11 | "date":"8/27/2018",
12 | "value":2
13 | },
14 | {
15 | "date":"8/28/2018",
16 | "value":3
17 | },
18 | {
19 | "date":"8/29/2018",
20 | "value":3
21 | },
22 | {
23 | "date":"8/30/2018",
24 | "value":2
25 | },
26 | {
27 | "date":"8/31/2018",
28 | "value":6
29 | },
30 | {
31 | "date":"9/1/2018",
32 | "value":3
33 | },
34 | {
35 | "date":"9/2/2018",
36 | "value":10
37 | },
38 | {
39 | "date":"9/3/2018",
40 | "value":3
41 | },
42 | {
43 | "date":"9/4/2018",
44 | "value":8
45 | },
46 | {
47 | "date":"9/5/2018",
48 | "value":3
49 | },
50 | {
51 | "date":"9/6/2018",
52 | "value":3
53 | },
54 | {
55 | "date":"9/7/2018",
56 | "value":6
57 | },
58 | {
59 | "date":"9/8/2018",
60 | "value":6
61 | },
62 | {
63 | "date":"9/9/2018",
64 | "value":4
65 | },
66 | {
67 | "date":"9/10/2018",
68 | "value":6
69 | },
70 | {
71 | "date":"9/11/2018",
72 | "value":7
73 | },
74 | {
75 | "date":"9/12/2018",
76 | "value":4
77 | },
78 | {
79 | "date":"9/14/2018",
80 | "value":7
81 | },
82 | {
83 | "date":"9/15/2018",
84 | "value":11
85 | },
86 | {
87 | "date":"9/16/2018",
88 | "value":13
89 | },
90 | {
91 | "date":"9/17/2018",
92 | "value":5
93 | },
94 | {
95 | "date":"9/18/2018",
96 | "value":5
97 | },
98 | {
99 | "date":"9/19/2018",
100 | "value":1
101 | },
102 | {
103 | "date":"9/20/2018",
104 | "value":1
105 | },
106 | {
107 | "date":"9/21/2018",
108 | "value":4
109 | },
110 | {
111 | "date":"9/22/2018",
112 | "value":1
113 | },
114 | {
115 | "date":"9/23/2018",
116 | "value":1
117 | },
118 | {
119 | "date":"9/24/2018",
120 | "value":4
121 | },
122 | {
123 | "date":"9/27/2018",
124 | "value":1
125 | },
126 | {
127 | "date":"9/28/2018",
128 | "value":1
129 | },
130 | {
131 | "date":"9/29/2018",
132 | "value":4
133 | },
134 | {
135 | "date":"10/1/2018",
136 | "value":1
137 | },
138 | {
139 | "date":"10/2/2018",
140 | "value":1
141 | },
142 | {
143 | "date":"10/4/2018",
144 | "value":2
145 | },
146 | {
147 | "date":"10/6/2018",
148 | "value":1
149 | },
150 | {
151 | "date":"10/7/2018",
152 | "value":2
153 | },
154 | {
155 | "date":"10/11/2018",
156 | "value":3
157 | },
158 | {
159 | "date":"10/14/2018",
160 | "value":2
161 | },
162 | {
163 | "date":"10/20/2018",
164 | "value":1
165 | },
166 | {
167 | "date":"10/21/2018",
168 | "value":1
169 | },
170 | {
171 | "date":"10/22/2018",
172 | "value":1
173 | },
174 | {
175 | "date":"10/23/2018",
176 | "value":1
177 | },
178 | {
179 | "date":"11/8/2018",
180 | "value":1
181 | },
182 | {
183 | "date":"11/9/2018",
184 | "value":1
185 | },
186 | {
187 | "date":"11/12/2018",
188 | "value":1
189 | },
190 | {
191 | "date":"11/28/2018",
192 | "value":1
193 | },
194 | {
195 | "date":"12/9/2018",
196 | "value":1
197 | }
198 | ]
--------------------------------------------------------------------------------
/src/processors/formats.js:
--------------------------------------------------------------------------------
1 | import * as d3 from 'd3-format';
2 | import moment from 'moment';
3 |
4 | const spacize = (str) => {
5 | return str.split('_').join(' ');
6 | }
7 |
8 | //abc of abc -> Abc of Abc
9 | const capitalize = (str) => {
10 | // add as dataset grows
11 | const preps = ['on', 'at', 'in', 'of', 'with'];
12 | return str.split('_').join(' ').split(' ').map(word => {
13 | if (preps.indexOf(word) > -1) {
14 | return word;
15 | } else {
16 | return word[0].charAt(0).toUpperCase() + word.slice(1);
17 | }
18 | }).join(' ');
19 | }
20 |
21 | //e.g., 1200 unit -> 1,200 units
22 | const pluralize = (n, unit, total) => {
23 | if (n === total) {
24 | return `every ${unit}`;
25 | } else {
26 | return `${n.toLocaleString()} ${unit}${n !== 1 ? `s`: ``}`;
27 | }
28 | }
29 |
30 | const locale = (n, decimal) => {
31 | const pow = decimal || 1;
32 | return (Math.round(n * Math.pow(10, pow)) / Math.pow(10, pow)).toLocaleString();
33 | }
34 |
35 | //add SI prefix - k, M...
36 | const prefix = (n) => {
37 | if (n === 0) {
38 | return 0;
39 | } else if (n >= 0.0001 && n < 10000) {
40 | return n;
41 | } else {
42 | return d3.format('.2s')(n);
43 | }
44 | }
45 |
46 | const getMomentDay = (year, unit, id) => {
47 | return moment(year, 'YYYY').add(id, `${unit}s`);
48 | }
49 |
50 | const getDurationAcrossMonth = (sd, ed, isDay) => {
51 | //start day format
52 | let sf = 'MMMM D';
53 | //end day format
54 | let ef;
55 | if (isDay) {
56 | sf = 'ddd MMM D';
57 | ef = 'ddd MMM D';
58 | } else {
59 | ef = sd.format('M') === ed.format('M') ? `D` : `MMMM D`;
60 | }
61 | return `${sd.format(sf)} - ${ed.format(ef)}`;
62 | }
63 |
64 | const humanizeUnitId = (year, unit, id) => {
65 | const d = year != null ? getMomentDay(year, unit, id) : moment(id, 'M/D/YYYY');
66 | if (unit === 'day') {
67 | return d.format('ddd MMM D');
68 | } else if (unit === 'week') {
69 | const sd = d.startOf(id === 0 ? 'year' : 'week');
70 | const ed = sd.clone().add(6, 'days');
71 | return getDurationAcrossMonth(sd, ed);
72 | } else {
73 | return moment(+id + 1, 'M').format('MMMM');
74 | }
75 | }
76 |
77 | const humanizeDuration = (year, unit, id, count) => {
78 | if (count === 1) {
79 | return humanizeUnitId(year, unit, id);
80 | }
81 | let sd;
82 | if (unit === 'day') {
83 | sd = getMomentDay(year, unit, id);
84 | } else if (unit === 'week') {
85 | sd = getMomentDay(year, unit, id).startOf(id === 0 ? 'year' : 'week');
86 | } else {
87 | sd = moment(unit + 1, 'M');
88 | }
89 | let ed;
90 | if (unit === 'day') {
91 | ed = sd.clone().add(count - 1, 'days');
92 | } else if (unit === 'week') {
93 | ed = sd.clone().add((count - 1) * 7 + 6, 'days');
94 | } else {
95 | ed = moment(id + count, 'M');
96 | }
97 | let finalStr;
98 | if (unit === 'month') {
99 | finalStr = `${sd.format('MMMM')} - ${ed.format('MMMM')}`;
100 | } else {
101 | finalStr = getDurationAcrossMonth(sd, ed, true);
102 | }
103 | return finalStr;
104 | }
105 |
106 | const pronoun = (gender, isHead) => {
107 | let pn = 'xe';
108 | if (gender === 'female') {
109 | pn = 'she';
110 | } else if (gender === 'male') {
111 | pn = 'he';
112 | }
113 | return isHead ? capitalize(pn) : pn;
114 | }
115 |
116 | export {spacize, capitalize, pluralize, locale, prefix, humanizeUnitId, humanizeDuration, pronoun};
--------------------------------------------------------------------------------
/src/data/tanyofish-tweeted-on-tvxq-2018.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "date":"3/30/2018",
4 | "value":1
5 | },
6 | {
7 | "date":"10/2/2018",
8 | "value":1
9 | },
10 | {
11 | "date":"10/7/2018",
12 | "value":18
13 | },
14 | {
15 | "date":"10/8/2018",
16 | "value":4
17 | },
18 | {
19 | "date":"10/9/2018",
20 | "value":7
21 | },
22 | {
23 | "date":"10/13/2018",
24 | "value":3
25 | },
26 | {
27 | "date":"10/14/2018",
28 | "value":14
29 | },
30 | {
31 | "date":"10/15/2018",
32 | "value":9
33 | },
34 | {
35 | "date":"10/16/2018",
36 | "value":9
37 | },
38 | {
39 | "date":"10/18/2018",
40 | "value":5
41 | },
42 | {
43 | "date":"10/19/2018",
44 | "value":1
45 | },
46 | {
47 | "date":"10/20/2018",
48 | "value":5
49 | },
50 | {
51 | "date":"10/21/2018",
52 | "value":12
53 | },
54 | {
55 | "date":"10/22/2018",
56 | "value":21
57 | },
58 | {
59 | "date":"10/23/2018",
60 | "value":29
61 | },
62 | {
63 | "date":"10/24/2018",
64 | "value":8
65 | },
66 | {
67 | "date":"10/25/2018",
68 | "value":8
69 | },
70 | {
71 | "date":"10/26/2018",
72 | "value":9
73 | },
74 | {
75 | "date":"10/27/2018",
76 | "value":7
77 | },
78 | {
79 | "date":"10/28/2018",
80 | "value":4
81 | },
82 | {
83 | "date":"10/29/2018",
84 | "value":6
85 | },
86 | {
87 | "date":"10/30/2018",
88 | "value":3
89 | },
90 | {
91 | "date":"10/31/2018",
92 | "value":10
93 | },
94 | {
95 | "date":"11/1/2018",
96 | "value":4
97 | },
98 | {
99 | "date":"11/2/2018",
100 | "value":5
101 | },
102 | {
103 | "date":"11/4/2018",
104 | "value":2
105 | },
106 | {
107 | "date":"11/5/2018",
108 | "value":5
109 | },
110 | {
111 | "date":"11/6/2018",
112 | "value":1
113 | },
114 | {
115 | "date":"11/7/2018",
116 | "value":1
117 | },
118 | {
119 | "date":"11/9/2018",
120 | "value":2
121 | },
122 | {
123 | "date":"11/11/2018",
124 | "value":5
125 | },
126 | {
127 | "date":"11/12/2018",
128 | "value":8
129 | },
130 | {
131 | "date":"11/13/2018",
132 | "value":4
133 | },
134 | {
135 | "date":"11/14/2018",
136 | "value":4
137 | },
138 | {
139 | "date":"11/15/2018",
140 | "value":4
141 | },
142 | {
143 | "date":"11/16/2018",
144 | "value":1
145 | },
146 | {
147 | "date":"11/17/2018",
148 | "value":3
149 | },
150 | {
151 | "date":"11/19/2018",
152 | "value":2
153 | },
154 | {
155 | "date":"11/20/2018",
156 | "value":1
157 | },
158 | {
159 | "date":"11/25/2018",
160 | "value":1
161 | },
162 | {
163 | "date":"11/26/2018",
164 | "value":1
165 | },
166 | {
167 | "date":"11/28/2018",
168 | "value":5
169 | },
170 | {
171 | "date":"11/30/2018",
172 | "value":1
173 | },
174 | {
175 | "date":"12/1/2018",
176 | "value":1
177 | },
178 | {
179 | "date":"12/4/2018",
180 | "value":1
181 | },
182 | {
183 | "date":"12/12/2018",
184 | "value":1
185 | },
186 | {
187 | "date":"12/16/2018",
188 | "value":1
189 | },
190 | {
191 | "date":"12/18/2018",
192 | "value":1
193 | },
194 | {
195 | "date":"12/19/2018",
196 | "value":6
197 | },
198 | {
199 | "date":"12/23/2018",
200 | "value":2
201 | },
202 | {
203 | "date":"12/24/2018",
204 | "value":1
205 | }
206 | ]
--------------------------------------------------------------------------------
/src/components/vis/BarChart.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import DayTexts from './DayTexts';
3 | import {getMaxColor, getColorForNegative} from './../../processors/colors';
4 | import {getDataByDay} from './../../processors/analysis';
5 | import * as d3 from 'd3';
6 |
7 | class Bars extends Component {
8 | render() {
9 | const {dim, xScale, barScale, color, data} = this.props;
10 |
11 | const colorPositive = getMaxColor(color);
12 | const colorNevative = getColorForNegative(color);
13 |
14 | const bars = data.map((d, i) => {
15 | const width = barScale(Math.abs(d));
16 | return (
17 |
18 | = 0 ? xScale(0) : xScale(0) - width}
20 | y={i * dim.barH + dim.barH / 8}
21 | width={width}
22 | height={dim.barH / 8 * 6}
23 | fill={d >=0 ? colorPositive : colorNevative}
24 | />
25 |
31 | {d.toLocaleString()}
32 |
33 |
34 | );
35 | });
36 |
37 | return (
38 |
39 | {bars}
40 |
41 | );
42 | }
43 | }
44 |
45 | class Axis extends Component {
46 | componentDidMount() {
47 | this.renderAxis();
48 | }
49 | componentDidUpdate() {
50 | this.renderAxis();
51 | }
52 | renderAxis() {
53 | d3.select('#axis')
54 | .call(d3
55 | .axisBottom(this.props.scale)
56 | .tickFormat(d3.format('.2s'))
57 | .tickSize(-this.props.dim.h)
58 | .tickPadding(9)
59 | .ticks(8)
60 | );
61 | }
62 |
63 | render() {
64 | const {dim} = this.props;
65 | return (
66 |
70 | );
71 | }
72 | }
73 |
74 | class BarChart extends Component {
75 | render() {
76 | const {selection, dims, color} = this.props;
77 | const {containerW, h, margin} = dims;
78 | const chartDim = {
79 | w: containerW - margin.left - margin.right,
80 | h: h * 2,
81 | barH: h * 2 / 7,
82 | margin: {
83 | top: 20,
84 | right: 80,
85 | left: dims.margin.left,
86 | bottom: 40
87 | }
88 | };
89 |
90 | const data = getDataByDay(this.props.data);
91 | const maxVal = Math.max(...data.map((d) => d[selection]));
92 | const minVal = Math.min(...data.map((d) => d[selection]));
93 |
94 | // for axis
95 | const xScale = d3.scaleLinear()
96 | .domain([Math.min(minVal, 0), Math.max(maxVal, 0)])
97 | .range([0, chartDim.w]);
98 |
99 | // bars across from negative to positive values
100 | const barScale = d3.scaleLinear()
101 | .domain([0, Math.max(maxVal, 0) - Math.min(minVal, 0)])
102 | .range([0, chartDim.w]);
103 |
104 | return (
105 |
119 | );
120 | }
121 | }
122 |
123 | export default BarChart;
--------------------------------------------------------------------------------
/src/data/tanyofish-swimming-2017.json:
--------------------------------------------------------------------------------
1 | [{"date":"1/2/2017","value":2700},{"date":"1/6/2017","value":2000},{"date":"1/8/2017","value":3281},{"date":"1/11/2017","value":1800},{"date":"1/13/2017","value":2200},{"date":"1/14/2017","value":1550},{"date":"1/16/2017","value":3000},{"date":"1/21/2017","value":2900},{"date":"1/22/2017","value":3500},{"date":"1/24/2017","value":3500},{"date":"1/26/2017","value":500},{"date":"1/28/2017","value":2200},{"date":"1/29/2017","value":1800},{"date":"1/31/2017","value":3000},{"date":"2/2/2017","value":1900},{"date":"2/4/2017","value":2400},{"date":"2/5/2017","value":3500},{"date":"2/7/2017","value":1800},{"date":"2/11/2017","value":2000},{"date":"2/14/2017","value":3600},{"date":"2/16/2017","value":2600},{"date":"2/18/2017","value":2200},{"date":"2/24/2017","value":1800},{"date":"2/25/2017","value":2200},{"date":"2/28/2017","value":2700},{"date":"3/2/2017","value":3800},{"date":"3/3/2017","value":300},{"date":"3/5/2017","value":2843},{"date":"3/7/2017","value":3600},{"date":"3/10/2017","value":2200},{"date":"3/11/2017","value":2300},{"date":"3/14/2017","value":2000},{"date":"3/16/2017","value":3400},{"date":"3/18/2017","value":2600},{"date":"3/21/2017","value":1600},{"date":"3/23/2017","value":1900},{"date":"3/24/2017","value":2900},{"date":"3/26/2017","value":3171},{"date":"3/30/2017","value":2100},{"date":"4/1/2017","value":2100},{"date":"4/4/2017","value":3400},{"date":"4/7/2017","value":2200},{"date":"4/9/2017","value":3390},{"date":"4/11/2017","value":3550},{"date":"4/14/2017","value":1900},{"date":"4/16/2017","value":2400},{"date":"4/19/2017","value":2200},{"date":"4/21/2017","value":1800},{"date":"4/25/2017","value":2800},{"date":"4/28/2017","value":3600},{"date":"4/29/2017","value":1700},{"date":"5/2/2017","value":3500},{"date":"5/4/2017","value":2000},{"date":"5/5/2017","value":1600},{"date":"5/6/2017","value":2500},{"date":"5/9/2017","value":3400},{"date":"5/11/2017","value":3300},{"date":"5/13/2017","value":2200},{"date":"5/16/2017","value":3100},{"date":"5/19/2017","value":2400},{"date":"5/20/2017","value":2200},{"date":"6/9/2017","value":2100},{"date":"6/10/2017","value":1700},{"date":"6/13/2017","value":2400},{"date":"7/1/2017","value":2200},{"date":"7/6/2017","value":3100},{"date":"7/8/2017","value":2200},{"date":"7/9/2017","value":2843},{"date":"7/11/2017","value":3300},{"date":"7/13/2017","value":2600},{"date":"7/15/2017","value":2200},{"date":"7/18/2017","value":2700},{"date":"7/20/2017","value":2500},{"date":"7/22/2017","value":2200},{"date":"7/25/2017","value":2600},{"date":"7/28/2017","value":2300},{"date":"7/29/2017","value":2200},{"date":"7/31/2017","value":1900},{"date":"8/3/2017","value":3100},{"date":"8/10/2017","value":3900},{"date":"8/19/2017","value":2200},{"date":"8/22/2017","value":2600},{"date":"8/23/2017","value":2200},{"date":"8/24/2017","value":2750},{"date":"8/26/2017","value":2400},{"date":"9/6/2017","value":2734},{"date":"9/8/2017","value":2406},{"date":"9/19/2017","value":1950},{"date":"9/22/2017","value":2200},{"date":"9/23/2017","value":2500},{"date":"9/24/2017","value":2953},{"date":"9/26/2017","value":2900},{"date":"10/10/2017","value":2500},{"date":"10/12/2017","value":2600},{"date":"10/14/2017","value":2600},{"date":"10/16/2017","value":2500},{"date":"10/17/2017","value":2500},{"date":"10/23/2017","value":2200},{"date":"10/24/2017","value":2800},{"date":"10/25/2017","value":2550},{"date":"10/26/2017","value":3000},{"date":"10/27/2017","value":2300},{"date":"10/28/2017","value":2000},{"date":"11/2/2017","value":2300},{"date":"11/4/2017","value":2400},{"date":"11/5/2017","value":3390},{"date":"11/11/2017","value":2200},{"date":"11/14/2017","value":3100},{"date":"11/18/2017","value":2100},{"date":"11/22/2017","value":3300},{"date":"11/28/2017","value":2900},{"date":"12/1/2017","value":2000},{"date":"12/2/2017","value":2300},{"date":"12/4/2017","value":2100},{"date":"12/6/2017","value":2100},{"date":"12/12/2017","value":2800},{"date":"12/16/2017","value":2200},{"date":"12/19/2017","value":3000},{"date":"12/21/2017","value":3100},{"date":"12/30/2017","value":2400}]
--------------------------------------------------------------------------------
/src/components/vis/Blocks.js:
--------------------------------------------------------------------------------
1 | import React, {Component} from 'react';
2 | import moment from 'moment';
3 | import {getPoints, getAreaPath} from './../../processors/dimensions';
4 | import {getWeek} from './../../processors/analysis';
5 | import {getBlockColor} from './../../processors/colors';
6 |
7 | class Block extends Component {
8 | constructor(props) {
9 | super(props);
10 | this.onMouseOver = this.onMouseOver.bind(this);
11 | this.onMouseOut = this.onMouseOut.bind(this);
12 | }
13 | onMouseOver(e) {
14 | e.preventDefault()
15 | this.props.rectHovered(true, this.props.x, this.props.y, this.props.id, this.props.value, this.props.altValue);
16 | }
17 | onMouseOut(e) {
18 | e.preventDefault()
19 | this.props.rectHovered(false);
20 | }
21 | }
22 |
23 | // day, month, year block
24 | class Rect extends Block {
25 | render() {
26 | const {x, y, width, height, fill} = this.props;
27 | const svgProp = {x, y, width, height, fill};
28 | return ;
35 | }
36 | }
37 |
38 | class Line extends Block {
39 | render() {
40 | const {x, y, y2, stroke, strokeWidth} = this.props;
41 | const svgProp = {x1: x, x2: x, y1: y, y2, stroke, strokeWidth}
42 | return ;
49 | }
50 | }
51 |
52 | class Path extends Block {
53 | render() {
54 | return ;
62 | }
63 | }
64 |
65 | class Blocks extends Component {
66 |
67 | render() {
68 | const {rectW, data, rectHovered, calendar, year, h, margin, unit, brewer} = this.props;
69 | const {steps} = calendar.range[unit];
70 | const dataByUnit = ['week', 'month'].map(unit => Object.entries(calendar.byUnit[unit]).map(d => [+d[0], d[1]]));
71 | const svgByUnit = {
72 | day: data.map(item =>
73 | ),
85 | week: dataByUnit[0].map(item =>
86 | ),
97 | month: dataByUnit[1].map((item, i) => {
98 | const path = getAreaPath(rectW, h, margin, year, item[0]);
99 | const points = getPoints(rectW, h, margin, year, item[0]);
100 | return ();
110 | }),
111 | };
112 |
113 | return (
114 |
115 | {svgByUnit[unit]}
116 |
117 | );
118 | }
119 | }
120 |
121 | export default Blocks;
--------------------------------------------------------------------------------
/src/data/plabinu-swimming-2017.json:
--------------------------------------------------------------------------------
1 | [{"date":"1/2/2017","value":1850},{"date":"1/4/2017","value":1250},{"date":"1/6/2017","value":1350},{"date":"1/9/2017","value":1850},{"date":"1/11/2017","value":1300},{"date":"1/13/2017","value":1650},{"date":"1/16/2017","value":1850},{"date":"1/18/2017","value":1500},{"date":"1/23/2017","value":1800},{"date":"1/25/2017","value":1700},{"date":"2/1/2017","value":1300},{"date":"2/3/2017","value":1400},{"date":"2/6/2017","value":1850},{"date":"2/8/2017","value":1250},{"date":"2/10/2017","value":1350},{"date":"2/13/2017","value":1950},{"date":"2/15/2017","value":1250},{"date":"2/17/2017","value":1450},{"date":"2/20/2017","value":1800},{"date":"2/22/2017","value":1350},{"date":"2/24/2017","value":1400},{"date":"2/27/2017","value":1900},{"date":"3/3/2017","value":1400},{"date":"3/6/2017","value":1800},{"date":"3/8/2017","value":700},{"date":"3/10/2017","value":1400},{"date":"3/13/2017","value":1750},{"date":"3/15/2017","value":700},{"date":"3/17/2017","value":1450},{"date":"3/20/2017","value":1550},{"date":"3/22/2017","value":800},{"date":"3/24/2017","value":1550},{"date":"3/27/2017","value":1600},{"date":"3/29/2017","value":800},{"date":"3/31/2017","value":1300},{"date":"4/3/2017","value":1400},{"date":"4/5/2017","value":1150},{"date":"4/7/2017","value":1450},{"date":"4/10/2017","value":1700},{"date":"4/12/2017","value":1000},{"date":"4/14/2017","value":1400},{"date":"4/17/2017","value":1500},{"date":"4/19/2017","value":1000},{"date":"4/21/2017","value":1400},{"date":"4/24/2017","value":1700},{"date":"4/26/2017","value":1400},{"date":"4/28/2017","value":1600},{"date":"5/8/2017","value":1750},{"date":"5/10/2017","value":1000},{"date":"5/12/2017","value":1100},{"date":"5/17/2017","value":1800},{"date":"5/19/2017","value":1450},{"date":"5/22/2017","value":1650},{"date":"5/24/2017","value":1000},{"date":"5/26/2017","value":1300},{"date":"5/29/2017","value":1500},{"date":"6/5/2017","value":1750},{"date":"6/7/2017","value":1000},{"date":"6/12/2017","value":1750},{"date":"6/14/2017","value":1000},{"date":"6/16/2017","value":1400},{"date":"6/19/2017","value":2000},{"date":"6/21/2017","value":1000},{"date":"6/23/2017","value":1400},{"date":"6/26/2017","value":1850},{"date":"7/5/2017","value":1000},{"date":"7/7/2017","value":1400},{"date":"7/10/2017","value":1850},{"date":"7/12/2017","value":1000},{"date":"7/14/2017","value":1350},{"date":"7/17/2017","value":1650},{"date":"7/19/2017","value":1000},{"date":"7/21/2017","value":1300},{"date":"7/24/2017","value":1850},{"date":"7/26/2017","value":1100},{"date":"7/28/2017","value":1000},{"date":"8/2/2017","value":1000},{"date":"8/4/2017","value":1300},{"date":"8/7/2017","value":2100},{"date":"8/9/2017","value":1400},{"date":"8/14/2017","value":1850},{"date":"8/16/2017","value":1450},{"date":"8/18/2017","value":1400},{"date":"8/21/2017","value":1950},{"date":"8/23/2017","value":1450},{"date":"8/25/2017","value":1350},{"date":"8/28/2017","value":1850},{"date":"8/30/2017","value":1750},{"date":"9/1/2017","value":1350},{"date":"9/4/2017","value":1700},{"date":"9/6/2017","value":1400},{"date":"9/8/2017","value":1200},{"date":"9/11/2017","value":1700},{"date":"9/13/2017","value":1300},{"date":"9/18/2017","value":1750},{"date":"9/20/2017","value":1450},{"date":"9/22/2017","value":1450},{"date":"9/27/2017","value":1450},{"date":"9/29/2017","value":1000},{"date":"10/11/2017","value":1000},{"date":"10/13/2017","value":1300},{"date":"10/16/2017","value":1550},{"date":"10/18/2017","value":1300},{"date":"10/23/2017","value":1850},{"date":"10/25/2017","value":1200},{"date":"10/30/2017","value":1800},{"date":"11/1/2017","value":1000},{"date":"11/3/2017","value":1200},{"date":"11/6/2017","value":1300},{"date":"11/8/2017","value":1100},{"date":"11/10/2017","value":1200},{"date":"11/13/2017","value":1500},{"date":"11/15/2017","value":1200},{"date":"11/20/2017","value":1700},{"date":"11/22/2017","value":800},{"date":"11/24/2017","value":950},{"date":"11/27/2017","value":1500},{"date":"12/1/2017","value":1450},{"date":"12/4/2017","value":1450},{"date":"12/6/2017","value":1550},{"date":"12/8/2017","value":1500},{"date":"12/11/2017","value":1000},{"date":"12/13/2017","value":1250},{"date":"12/18/2017","value":1700},{"date":"12/20/2017","value":1200},{"date":"12/27/2017","value":1000},{"date":"12/29/2017","value":1400}]
--------------------------------------------------------------------------------
/src/settings/datasets.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "year": 2023,
4 | "data": [
5 | {
6 | "author": "tanyofish",
7 | "topic": "swimming"
8 | },
9 | {
10 | "author": "tanyoung",
11 | "topic": "steps"
12 | }
13 | ]
14 | },
15 | {
16 | "year": 2022,
17 | "data": [
18 | {
19 | "author": "tanyofish",
20 | "topic": "swimming"
21 | },
22 | {
23 | "author": "tanyoung",
24 | "topic": "steps"
25 | }
26 | ]
27 | },
28 | {
29 | "year": 2021,
30 | "data": [
31 | {
32 | "author": "tanyofish",
33 | "topic": "swimming"
34 | },
35 | {
36 | "author": "tanyoung",
37 | "topic": "steps"
38 | }
39 | ]
40 | },
41 | {
42 | "year": 2020,
43 | "data": [
44 | {
45 | "author": "tanyofish",
46 | "topic": "swimming"
47 | },
48 | {
49 | "author": "tanyoung",
50 | "topic": "steps"
51 | },
52 | {
53 | "author": "tanyoung",
54 | "topic": "flights climbed"
55 | },
56 | {
57 | "author": "tanyofish",
58 | "topic": "twitter"
59 | },
60 | {
61 | "author": "dr. lancaster",
62 | "topic": "electricity usage"
63 | },
64 | {
65 | "author": "tanyoung",
66 | "topic": "piano_practice"
67 | },
68 | {
69 | "author": "tanykim",
70 | "topic": "time at dr._lancaster"
71 | }
72 | ]
73 | },
74 | {
75 | "year": 2019,
76 | "data": [
77 | {
78 | "author": "tanyofish",
79 | "topic": "swimming"
80 | },
81 | {
82 | "author": "tanyoung",
83 | "topic": "steps"
84 | },
85 | {
86 | "author": "tanyoung",
87 | "topic": "flights climbed"
88 | },
89 | {
90 | "author": "tanyofish",
91 | "topic": "twitter"
92 | },
93 | {
94 | "author": "dr. lancaster",
95 | "topic": "electricity usage"
96 | },
97 | {
98 | "author": "tanyoung",
99 | "topic": "piano_practice"
100 | },
101 | {
102 | "author": "tanykim",
103 | "topic": "time at dr._lancaster"
104 | }
105 | ]
106 | },
107 | {
108 | "year": 2018,
109 | "data": [
110 | {
111 | "author": "tanyofish",
112 | "topic": "swimming"
113 | },
114 | {
115 | "author": "tanyofish",
116 | "topic": "twitter"
117 | },
118 | {
119 | "author": "tanykim",
120 | "topic": "reactions on facebook"
121 | },
122 | {
123 | "author": "tanykim",
124 | "topic": "time at dr._lancaster"
125 | },
126 | {
127 | "author": "tanyoung",
128 | "topic": "steps"
129 | },
130 | {
131 | "author": "tanyoung",
132 | "topic": "flights climbed"
133 | },
134 | {
135 | "author": "dr. lancaster",
136 | "topic": "electricity usage"
137 | },
138 | {
139 | "author": "mr. moon",
140 | "topic": "driving"
141 | }
142 | ]
143 | },
144 | {
145 | "year": 2017,
146 | "data": [
147 | {
148 | "author": "tanyofish",
149 | "topic": "swimming"
150 | },
151 | {
152 | "author": "tanyofish",
153 | "topic": "twitter"
154 | }
155 | ]
156 | },
157 | {
158 | "year": 2016,
159 | "data": [
160 | {
161 | "author": "tanyofish",
162 | "topic": "swimming"
163 | },
164 | {
165 | "author": "tanyofish",
166 | "topic": "twitter"
167 | },
168 | {
169 | "author": "tanyoung",
170 | "topic": "time at cafe"
171 | },
172 | {
173 | "author": "tanyoung",
174 | "topic": "time at marty's"
175 | }
176 | ]
177 | },
178 | {
179 | "year": 2015,
180 | "data": [
181 | {
182 | "author": "tanyofish",
183 | "topic": "twitter"
184 | }
185 | ]
186 | },
187 | {
188 | "year": 2014,
189 | "data": [
190 | {
191 | "author": "tanyofish",
192 | "topic": "twitter"
193 | }
194 | ]
195 | },
196 | {
197 | "year": 2013,
198 | "data": [
199 | {
200 | "author": "tanyofish",
201 | "topic": "twitter"
202 | }
203 | ]
204 | }
205 | ]
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Menu from './components/Menu';
3 | import Summary from './components/Summary';
4 | import Main from './components/Main';
5 | import ByDay from './components/ByDay';
6 | import { capitalize } from './processors/formats';
7 | import { getColorForTwoDirection, getRandomColor } from './processors/colors';
8 | import { getVisDimensions } from './processors/dimensions';
9 | import { getConvertedData } from './processors/analysis';
10 |
11 | import { Icon } from 'react-fa';
12 |
13 | class App extends Component {
14 | constructor(props) {
15 | super(props);
16 | this.state = {
17 | menuOpen: false,
18 | isScrolled: false,
19 | };
20 |
21 | this.handleScroll = this.handleScroll.bind(this);
22 | this.toggleMenu = this.toggleMenu.bind(this);
23 | }
24 |
25 | componentDidMount() {
26 | window.addEventListener('scroll', this.handleScroll);
27 | }
28 |
29 | handleScroll() {
30 | const scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
31 | this.setState({ isScrolled: scrollTop > 180 });
32 | }
33 |
34 | toggleMenu(willClose) {
35 | this.setState({ menuOpen: !willClose || !this.state.menuOpen });
36 | }
37 |
38 | render() {
39 | // get data id from url
40 | const dataId = this.props.params.dataId || 'tanyofish-swimming-2020';
41 | const setting = require(`./settings/${dataId}.json`);
42 | let data = require(`./data/${dataId}.json`);
43 | let { author, topic, year, color, abbr, alt_unit, conversion, decimal, hasNegative, isReverse } = setting;
44 | // if alternaitve unit exists
45 | if (alt_unit != null) {
46 | data = getConvertedData(data, conversion, decimal);
47 | }
48 | if (hasNegative) {
49 | color = getColorForTwoDirection(isReverse);
50 | } else if (color === undefined && !hasNegative) {
51 | color = getRandomColor();
52 | }
53 | setting.color = color;
54 | if (abbr === undefined) {
55 | abbr = ' ' + setting.metric + 's';
56 | setting.abbr = abbr;
57 | }
58 | const dims = getVisDimensions(year);
59 | return (
60 |
61 |
62 |
63 |
64 | Datasets
65 |
66 |
67 |
68 |
69 |
70 |
71 |
{capitalize(author)}'s
72 |
{capitalize(topic)} in {year}
73 |
74 |
78 |
83 |
88 |
113 |
114 | );
115 | }
116 | }
117 |
118 | export default App;
119 |
--------------------------------------------------------------------------------
/src/index.less:
--------------------------------------------------------------------------------
1 | @import 'less/colors';
2 |
3 | body {
4 | margin: 0;
5 | padding: 0;
6 | color: @main;
7 | }
8 |
9 | .hide {
10 | display: hide;
11 | }
12 | .show {
13 | display: block;
14 | }
15 | .show-inline {
16 | display: inline;
17 | }
18 |
19 | .header {
20 | padding-bottom: 36px;
21 | position: relative;
22 | .author {
23 | font-size: 24px;
24 | }
25 | .topic {
26 | font-size: 42px;
27 | font-weight: bold;
28 | line-height: 48px;
29 | }
30 | }
31 | .header-fixed {
32 | position: fixed;
33 | background-color: @main;
34 | text-align: center;
35 | width: 100%;
36 | left: 0;
37 | top: 0;
38 | z-index: 1000;
39 | padding-top: 12px;
40 | padding-bottom: 12px;
41 | -webkit-box-shadow: 0px 2px 4px 0px rgba(0,0,0,0.4);
42 | -moz-box-shadow: 0px 2px 4px 0px rgba(0,0,0,0.4);
43 | box-shadow: 0px 2px 4px 0px rgba(0,0,0,0.4);
44 | .author, .topic {
45 | color: #FFF !important;
46 | font-size: 16px;
47 | display: inline-block;
48 | }
49 | .author {
50 | margin-right: 8px;
51 | }
52 | }
53 | .menu {
54 | position: relative;
55 | top: 0;
56 | right: 0;
57 | padding-top: 24px;
58 | width: 100%;
59 | z-index: 1000;
60 | text-align: right;
61 | .menu-text {
62 | margin-bottom: 8px;
63 | }
64 | .menu-close {
65 | letter-spacing: 0.05em;
66 | }
67 | .menu-icon {
68 | cursor: pointer;
69 | }
70 | .menu-content {
71 | display: none;
72 | background-color: @main;
73 | position: fixed;
74 | top: 0;
75 | color: #fff;
76 | right: 0px;
77 | padding: 24px;
78 | text-align: left;
79 | height: 100%;
80 | .block {
81 | padding-top: 20px;
82 | margin-top: 20px;
83 | border-top:1px solid #495057;
84 | }
85 | .year {
86 | font-size: 12px;
87 | letter-spacing: 0.2em;
88 | margin-bottom: 12px;
89 | color: @sub;
90 | }
91 | .list {
92 | margin: 0;
93 | padding: 0;
94 | list-style: none;
95 | li {
96 | margin-bottom: 8px;
97 | letter-spacing: 0.02em;
98 | &:last-child {
99 | margin-bottom: 0px;
100 | }
101 | }
102 | li.selected {
103 | color: @sub;
104 | }
105 | a {
106 | color: #fff;
107 | text-decoration: none;
108 | }
109 | }
110 | }
111 | }
112 | .summary, .max, .stats, .byDay {
113 | padding-top: 48px;
114 | padding-bottom: 48px;
115 | font-weight: 500;
116 | font-size: 24px;
117 | line-height: 120%;
118 | }
119 | .summary, {
120 | border-top: 1px solid #e9ecef;
121 | border-bottom: 1px solid #e9ecef;
122 | }
123 | .fixed {
124 | overflow-x: auto;
125 | }
126 | .slider {
127 | color: #868e96;
128 | padding: 8px;
129 | font-size: 16px;
130 | }
131 | .max, .stats {
132 | border-bottom: 1px solid #e9ecef;
133 | }
134 | .summary, .stats, .footer {
135 | background-color: #f8f9fa;
136 | }
137 | .unit-selection {
138 | padding-top: 36px;
139 | padding-bottom: 24px;
140 | font-weight: 500;
141 | font-size: 18px;
142 | margin-bottom: -12px;
143 | .title {
144 | font-size: 24px;
145 | padding-bottom: 12px;
146 | }
147 | .input {
148 | display: inline-block;
149 | margin-right: 16px;
150 | &:last-child {
151 | margin-right: 0;
152 | }
153 | }
154 | input {
155 | margin-right: 8px;
156 | margin-left: 16px;
157 | &:first-child {
158 | margin-left: 0;
159 | }
160 | }
161 | }
162 | .legend {
163 | line-height: 90%;
164 | padding-top: 12px;
165 | .block {
166 | font-size: 1px;
167 | display: inline-block;
168 | }
169 | .label {
170 | font-size: 12px;
171 | text-align: center;
172 | color: @main;
173 | font-weight: normal;
174 | display: inline-block;
175 | }
176 | }
177 | .radios {
178 | text-align: right;
179 | }
180 | .highlight {
181 | font-style: normal;
182 | font-weight: normal;
183 | padding: 0 8px;
184 | }
185 | i {
186 | .highlight();
187 | color: #FFF;
188 | display: inline-block;
189 | margin-top: 4px;
190 | margin-bottom: 4px;
191 | }
192 | ii {
193 | .highlight();
194 | display: inline-block;
195 | margin-top: 4px;
196 | margin-bottom: 4px;
197 | }
198 | l {
199 | font-weight: 200;
200 | }
201 | .footer {
202 | font-size: 16px;
203 | margin-top: 36px;
204 | padding-top: 24px;
205 | padding-bottom: 24px;
206 | border-top: 1px solid #e9ecef;
207 | color: #868e96;
208 | .link {
209 | margin-right: 16px;
210 | padding-right: 16px;
211 | border-right: 1px solid #868e96;
212 | &:last-child {
213 | margin-right: 0;
214 | padding-right: 0;
215 | border-right: none;
216 | }
217 | a {
218 | margin-right: 6px;
219 | &:first-child {
220 | margin-left: 6px;
221 | };
222 | &:last-child {
223 | margin-right: 0;
224 | }
225 | }
226 | }
227 | }
228 |
229 | /* Medium devices (desktops, 992px and up) */
230 | @media (min-width: 992px) {
231 | .legend {
232 | text-align: right;
233 | padding-top: 0;
234 | }
235 | .menu-content {
236 | position: absolute !important;
237 | top: unset !important;
238 | height: unset !important;
239 | .block {
240 | &:first-child {
241 | border-top: none;
242 | padding-top: 0;
243 | margin-top: 0;
244 | }
245 | }
246 | }
247 | .menu-close {
248 | display: none;
249 | }
250 | }
251 |
252 | @import 'less/Visualization';
253 |
--------------------------------------------------------------------------------
/src/data/tanyoung-time-at-cafe-2016.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "date":"1/16/2016",
4 | "value":78
5 | },
6 | {
7 | "date":"1/23/2016",
8 | "value":87
9 | },
10 | {
11 | "date":"1/27/2016",
12 | "value":56
13 | },
14 | {
15 | "date":"1/30/2016",
16 | "value":214
17 | },
18 | {
19 | "date":"2/6/2016",
20 | "value":390
21 | },
22 | {
23 | "date":"2/9/2016",
24 | "value":354
25 | },
26 | {
27 | "date":"2/11/2016",
28 | "value":395
29 | },
30 | {
31 | "date":"2/14/2016",
32 | "value":185
33 | },
34 | {
35 | "date":"2/15/2016",
36 | "value":199
37 | },
38 | {
39 | "date":"2/19/2016",
40 | "value":244
41 | },
42 | {
43 | "date":"2/20/2016",
44 | "value":283
45 | },
46 | {
47 | "date":"3/26/2016",
48 | "value":221
49 | },
50 | {
51 | "date":"4/6/2016",
52 | "value":89
53 | },
54 | {
55 | "date":"4/8/2016",
56 | "value":35
57 | },
58 | {
59 | "date":"4/16/2016",
60 | "value":106
61 | },
62 | {
63 | "date":"4/17/2016",
64 | "value":233
65 | },
66 | {
67 | "date":"4/29/2016",
68 | "value":209
69 | },
70 | {
71 | "date":"5/6/2016",
72 | "value":119
73 | },
74 | {
75 | "date":"5/8/2016",
76 | "value":238
77 | },
78 | {
79 | "date":"5/11/2016",
80 | "value":204
81 | },
82 | {
83 | "date":"5/13/2016",
84 | "value":292
85 | },
86 | {
87 | "date":"5/18/2016",
88 | "value":181
89 | },
90 | {
91 | "date":"5/22/2016",
92 | "value":290
93 | },
94 | {
95 | "date":"5/24/2016",
96 | "value":101
97 | },
98 | {
99 | "date":"5/25/2016",
100 | "value":159
101 | },
102 | {
103 | "date":"5/26/2016",
104 | "value":57
105 | },
106 | {
107 | "date":"5/30/2016",
108 | "value":300
109 | },
110 | {
111 | "date":"6/7/2016",
112 | "value":55
113 | },
114 | {
115 | "date":"6/20/2016",
116 | "value":48
117 | },
118 | {
119 | "date":"6/22/2016",
120 | "value":133
121 | },
122 | {
123 | "date":"6/23/2016",
124 | "value":52
125 | },
126 | {
127 | "date":"6/26/2016",
128 | "value":85
129 | },
130 | {
131 | "date":"6/30/2016",
132 | "value":106
133 | },
134 | {
135 | "date":"7/1/2016",
136 | "value":161
137 | },
138 | {
139 | "date":"7/11/2016",
140 | "value":57
141 | },
142 | {
143 | "date":"7/14/2016",
144 | "value":143
145 | },
146 | {
147 | "date":"7/15/2016",
148 | "value":116
149 | },
150 | {
151 | "date":"7/16/2016",
152 | "value":151
153 | },
154 | {
155 | "date":"7/18/2016",
156 | "value":123
157 | },
158 | {
159 | "date":"7/24/2016",
160 | "value":129
161 | },
162 | {
163 | "date":"7/26/2016",
164 | "value":70
165 | },
166 | {
167 | "date":"8/4/2016",
168 | "value":121
169 | },
170 | {
171 | "date":"8/9/2016",
172 | "value":140
173 | },
174 | {
175 | "date":"8/13/2016",
176 | "value":110
177 | },
178 | {
179 | "date":"8/16/2016",
180 | "value":64
181 | },
182 | {
183 | "date":"8/17/2016",
184 | "value":232
185 | },
186 | {
187 | "date":"8/19/2016",
188 | "value":83
189 | },
190 | {
191 | "date":"8/20/2016",
192 | "value":105
193 | },
194 | {
195 | "date":"8/23/2016",
196 | "value":73
197 | },
198 | {
199 | "date":"8/24/2016",
200 | "value":57
201 | },
202 | {
203 | "date":"8/25/2016",
204 | "value":12
205 | },
206 | {
207 | "date":"8/27/2016",
208 | "value":138
209 | },
210 | {
211 | "date":"8/29/2016",
212 | "value":187
213 | },
214 | {
215 | "date":"9/1/2016",
216 | "value":109
217 | },
218 | {
219 | "date":"9/2/2016",
220 | "value":10
221 | },
222 | {
223 | "date":"9/4/2016",
224 | "value":294
225 | },
226 | {
227 | "date":"9/5/2016",
228 | "value":229
229 | },
230 | {
231 | "date":"9/7/2016",
232 | "value":138
233 | },
234 | {
235 | "date":"9/12/2016",
236 | "value":45
237 | },
238 | {
239 | "date":"9/13/2016",
240 | "value":115
241 | },
242 | {
243 | "date":"9/19/2016",
244 | "value":407
245 | },
246 | {
247 | "date":"9/20/2016",
248 | "value":86
249 | },
250 | {
251 | "date":"9/23/2016",
252 | "value":213
253 | },
254 | {
255 | "date":"10/5/2016",
256 | "value":195
257 | },
258 | {
259 | "date":"10/14/2016",
260 | "value":69
261 | },
262 | {
263 | "date":"10/20/2016",
264 | "value":164
265 | },
266 | {
267 | "date":"10/26/2016",
268 | "value":105
269 | },
270 | {
271 | "date":"10/28/2016",
272 | "value":204
273 | },
274 | {
275 | "date":"10/31/2016",
276 | "value":58
277 | },
278 | {
279 | "date":"11/2/2016",
280 | "value":383
281 | },
282 | {
283 | "date":"11/3/2016",
284 | "value":114
285 | },
286 | {
287 | "date":"11/4/2016",
288 | "value":60
289 | },
290 | {
291 | "date":"11/6/2016",
292 | "value":47
293 | },
294 | {
295 | "date":"11/8/2016",
296 | "value":246
297 | },
298 | {
299 | "date":"11/10/2016",
300 | "value":215
301 | },
302 | {
303 | "date":"11/11/2016",
304 | "value":193
305 | },
306 | {
307 | "date":"11/13/2016",
308 | "value":355
309 | },
310 | {
311 | "date":"11/22/2016",
312 | "value":179
313 | },
314 | {
315 | "date":"11/27/2016",
316 | "value":57
317 | },
318 | {
319 | "date":"12/8/2016",
320 | "value":175
321 | },
322 | {
323 | "date":"12/10/2016",
324 | "value":108
325 | },
326 | {
327 | "date":"12/13/2016",
328 | "value":71
329 | },
330 | {
331 | "date":"12/22/2016",
332 | "value":161
333 | },
334 | {
335 | "date":"12/31/2016",
336 | "value":172
337 | }
338 | ]
--------------------------------------------------------------------------------
/src/data/tanyoung-piano_practice-2020.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "date": "1/12/2020",
4 | "value": 31
5 | },
6 | {
7 | "date": "1/15/2020",
8 | "value": 36
9 | },
10 | {
11 | "date": "1/19/2020",
12 | "value": 19
13 | },
14 | {
15 | "date": "1/20/2020",
16 | "value": 33
17 | },
18 | {
19 | "date": "1/21/2020",
20 | "value": 26
21 | },
22 | {
23 | "date": "1/24/2020",
24 | "value": 27
25 | },
26 | {
27 | "date": "1/30/2020",
28 | "value": 10
29 | },
30 | {
31 | "date": "2/17/2020",
32 | "value": 18
33 | },
34 | {
35 | "date": "3/1/2020",
36 | "value": 24
37 | },
38 | {
39 | "date": "3/3/2020",
40 | "value": 14
41 | },
42 | {
43 | "date": "3/4/2020",
44 | "value": 26
45 | },
46 | {
47 | "date": "3/7/2020",
48 | "value": 17
49 | },
50 | {
51 | "date": "3/8/2020",
52 | "value": 11
53 | },
54 | {
55 | "date": "3/10/2020",
56 | "value": 34
57 | },
58 | {
59 | "date": "3/16/2020",
60 | "value": 8
61 | },
62 | {
63 | "date": "3/17/2020",
64 | "value": 7
65 | },
66 | {
67 | "date": "3/20/2020",
68 | "value": 19
69 | },
70 | {
71 | "date": "3/23/2020",
72 | "value": 24
73 | },
74 | {
75 | "date": "3/25/2020",
76 | "value": 10
77 | },
78 | {
79 | "date": "3/26/2020",
80 | "value": 55
81 | },
82 | {
83 | "date": "3/27/2020",
84 | "value": 41
85 | },
86 | {
87 | "date": "3/30/2020",
88 | "value": 35
89 | },
90 | {
91 | "date": "3/31/2020",
92 | "value": 34
93 | },
94 | {
95 | "date": "4/1/2020",
96 | "value": 30
97 | },
98 | {
99 | "date": "4/2/2020",
100 | "value": 38
101 | },
102 | {
103 | "date": "4/6/2020",
104 | "value": 45
105 | },
106 | {
107 | "date": "4/7/2020",
108 | "value": 54
109 | },
110 | {
111 | "date": "4/9/2020",
112 | "value": 31
113 | },
114 | {
115 | "date": "4/10/2020",
116 | "value": 51
117 | },
118 | {
119 | "date": "4/11/2020",
120 | "value": 11
121 | },
122 | {
123 | "date": "4/13/2020",
124 | "value": 64
125 | },
126 | {
127 | "date": "4/15/2020",
128 | "value": 86
129 | },
130 | {
131 | "date": "4/16/2020",
132 | "value": 20
133 | },
134 | {
135 | "date": "4/17/2020",
136 | "value": 40
137 | },
138 | {
139 | "date": "4/18/2020",
140 | "value": 94
141 | },
142 | {
143 | "date": "4/19/2020",
144 | "value": 77
145 | },
146 | {
147 | "date": "4/20/2020",
148 | "value": 125
149 | },
150 | {
151 | "date": "4/21/2020",
152 | "value": 72
153 | },
154 | {
155 | "date": "4/22/2020",
156 | "value": 16
157 | },
158 | {
159 | "date": "4/23/2020",
160 | "value": 72
161 | },
162 | {
163 | "date": "4/24/2020",
164 | "value": 50
165 | },
166 | {
167 | "date": "4/25/2020",
168 | "value": 61
169 | },
170 | {
171 | "date": "4/26/2020",
172 | "value": 12
173 | },
174 | {
175 | "date": "4/27/2020",
176 | "value": 63
177 | },
178 | {
179 | "date": "4/28/2020",
180 | "value": 106
181 | },
182 | {
183 | "date": "4/29/2020",
184 | "value": 86
185 | },
186 | {
187 | "date": "4/30/2020",
188 | "value": 52
189 | },
190 | {
191 | "date": "5/1/2020",
192 | "value": 22
193 | },
194 | {
195 | "date": "5/4/2020",
196 | "value": 40
197 | },
198 | {
199 | "date": "5/5/2020",
200 | "value": 34
201 | },
202 | {
203 | "date": "5/6/2020",
204 | "value": 38
205 | },
206 | {
207 | "date": "5/8/2020",
208 | "value": 41
209 | },
210 | {
211 | "date": "5/9/2020",
212 | "value": 51
213 | },
214 | {
215 | "date": "5/10/2020",
216 | "value": 54
217 | },
218 | {
219 | "date": "5/11/2020",
220 | "value": 26
221 | },
222 | {
223 | "date": "5/13/2020",
224 | "value": 18
225 | },
226 | {
227 | "date": "5/14/2020",
228 | "value": 21
229 | },
230 | {
231 | "date": "5/18/2020",
232 | "value": 14
233 | },
234 | {
235 | "date": "5/20/2020",
236 | "value": 41
237 | },
238 | {
239 | "date": "5/21/2020",
240 | "value": 82
241 | },
242 | {
243 | "date": "5/29/2020",
244 | "value": 13
245 | },
246 | {
247 | "date": "5/31/2020",
248 | "value": 30
249 | },
250 | {
251 | "date": "6/3/2020",
252 | "value": 14
253 | },
254 | {
255 | "date": "7/14/2020",
256 | "value": 18
257 | },
258 | {
259 | "date": "7/20/2020",
260 | "value": 29
261 | },
262 | {
263 | "date": "7/24/2020",
264 | "value": 23
265 | },
266 | {
267 | "date": "7/30/2020",
268 | "value": 17
269 | },
270 | {
271 | "date": "8/8/2020",
272 | "value": 32
273 | },
274 | {
275 | "date": "8/10/2020",
276 | "value": 55
277 | },
278 | {
279 | "date": "8/12/2020",
280 | "value": 49
281 | },
282 | {
283 | "date": "8/13/2020",
284 | "value": 43
285 | },
286 | {
287 | "date": "8/14/2020",
288 | "value": 89
289 | },
290 | {
291 | "date": "8/16/2020",
292 | "value": 52
293 | },
294 | {
295 | "date": "8/17/2020",
296 | "value": 150
297 | },
298 | {
299 | "date": "8/18/2020",
300 | "value": 50
301 | },
302 | {
303 | "date": "8/19/2020",
304 | "value": 18
305 | },
306 | {
307 | "date": "8/20/2020",
308 | "value": 39
309 | },
310 | {
311 | "date": "8/23/2020",
312 | "value": 55
313 | },
314 | {
315 | "date": "8/25/2020",
316 | "value": 14
317 | },
318 | {
319 | "date": "8/29/2020",
320 | "value": 43
321 | },
322 | {
323 | "date": "8/31/2020",
324 | "value": 10
325 | },
326 | {
327 | "date": "9/1/2020",
328 | "value": 53
329 | },
330 | {
331 | "date": "9/2/2020",
332 | "value": 70
333 | },
334 | {
335 | "date": "9/4/2020",
336 | "value": 63
337 | },
338 | {
339 | "date": "9/5/2020",
340 | "value": 62
341 | },
342 | {
343 | "date": "9/6/2020",
344 | "value": 26
345 | },
346 | {
347 | "date": "9/7/2020",
348 | "value": 18
349 | },
350 | {
351 | "date": "9/8/2020",
352 | "value": 45
353 | },
354 | {
355 | "date": "9/9/2020",
356 | "value": 44
357 | },
358 | {
359 | "date": "9/11/2020",
360 | "value": 16
361 | },
362 | {
363 | "date": "9/16/2020",
364 | "value": 21
365 | },
366 | {
367 | "date": "9/17/2020",
368 | "value": 47
369 | },
370 | {
371 | "date": "9/25/2020",
372 | "value": 10
373 | },
374 | {
375 | "date": "10/3/2020",
376 | "value": 35
377 | },
378 | {
379 | "date": "10/5/2020",
380 | "value": 24
381 | },
382 | {
383 | "date": "11/15/2020",
384 | "value": 22
385 | },
386 | {
387 | "date": "12/13/2020",
388 | "value": 39
389 | },
390 | {
391 | "date": "12/18/2020",
392 | "value": 35
393 | },
394 | {
395 | "date": "12/22/2020",
396 | "value": 28
397 | },
398 | {
399 | "date": "1/2/2021",
400 | "value": 32
401 | }
402 | ]
403 |
--------------------------------------------------------------------------------
/src/data/tanyofish-swimming-2020.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "date": "1/2/2020",
4 | "value": 2150
5 | },
6 | {
7 | "date": "1/4/2020",
8 | "value": 2800
9 | },
10 | {
11 | "date": "1/11/2020",
12 | "value": 2400
13 | },
14 | {
15 | "date": "1/12/2020",
16 | "value": 2500,
17 | "alt_unit": "m"
18 | },
19 | {
20 | "date": "1/14/2020",
21 | "value": 2000
22 | },
23 | {
24 | "date": "1/15/2020",
25 | "value": 2200
26 | },
27 | {
28 | "date": "1/18/2020",
29 | "value": 2500
30 | },
31 | {
32 | "date": "1/20/2020",
33 | "value": 2400
34 | },
35 | {
36 | "date": "1/25/2020",
37 | "value": 2300
38 | },
39 | {
40 | "date": "1/28/2020",
41 | "value": 2200
42 | },
43 | {
44 | "date": "1/30/2020",
45 | "value": 2300
46 | },
47 | {
48 | "date": "1/31/2020",
49 | "value": 2300
50 | },
51 | {
52 | "date": "2/2/2020",
53 | "value": 3000
54 | },
55 | {
56 | "date": "2/6/2020",
57 | "value": 2000
58 | },
59 | {
60 | "date": "2/8/2020",
61 | "value": 2400
62 | },
63 | {
64 | "date": "2/12/2020",
65 | "value": 2600
66 | },
67 | {
68 | "date": "2/14/2020",
69 | "value": 2100
70 | },
71 | {
72 | "date": "2/15/2020",
73 | "value": 2600
74 | },
75 | {
76 | "date": "2/16/2020",
77 | "value": 3700
78 | },
79 | {
80 | "date": "2/17/2020",
81 | "value": 2500
82 | },
83 | {
84 | "date": "2/20/2020",
85 | "value": 2200
86 | },
87 | {
88 | "date": "2/21/2020",
89 | "value": 2200
90 | },
91 | {
92 | "date": "2/22/2020",
93 | "value": 1600
94 | },
95 | {
96 | "date": "2/26/2020",
97 | "value": 2550
98 | },
99 | {
100 | "date": "2/27/2020",
101 | "value": 2750
102 | },
103 | {
104 | "date": "2/29/2020",
105 | "value": 2400
106 | },
107 | {
108 | "date": "3/1/2020",
109 | "value": 3700,
110 | "alt_unit": "m"
111 | },
112 | {
113 | "date": "3/6/2020",
114 | "value": 2700
115 | },
116 | {
117 | "date": "3/7/2020",
118 | "value": 2400
119 | },
120 | {
121 | "date": "3/10/2020",
122 | "value": 2050
123 | },
124 | {
125 | "date": "3/11/2020",
126 | "value": 3000
127 | },
128 | {
129 | "date": "3/12/2020",
130 | "value": 2600
131 | },
132 | {
133 | "date": "3/14/2020",
134 | "value": 2400
135 | },
136 | {
137 | "date": "3/15/2020",
138 | "value": 2500,
139 | "alt_unit": "m"
140 | },
141 | {
142 | "date": "6/30/2020",
143 | "value": 2500
144 | },
145 | {
146 | "date": "7/2/2020",
147 | "value": 2400
148 | },
149 | {
150 | "date": "7/8/2020",
151 | "value": 2600
152 | },
153 | {
154 | "date": "7/23/2020",
155 | "value": 2650
156 | },
157 | {
158 | "date": "7/28/2020",
159 | "value": 2400
160 | },
161 | {
162 | "date": "7/31/2020",
163 | "value": 2400
164 | },
165 | {
166 | "date": "8/3/2020",
167 | "value": 2700
168 | },
169 | {
170 | "date": "8/7/2020",
171 | "value": 2600
172 | },
173 | {
174 | "date": "8/10/2020",
175 | "value": 2200
176 | },
177 | {
178 | "date": "8/13/2020",
179 | "value": 2200
180 | },
181 | {
182 | "date": "8/19/2020",
183 | "value": 2600
184 | },
185 | {
186 | "date": "8/22/2020",
187 | "value": 2200
188 | },
189 | {
190 | "date": "8/27/2020",
191 | "value": 2500
192 | },
193 | {
194 | "date": "9/21/2020",
195 | "value": 2600
196 | },
197 | {
198 | "date": "9/24/2020",
199 | "value": 2600
200 | },
201 | {
202 | "date": "9/26/2020",
203 | "value": 2400
204 | },
205 | {
206 | "date": "9/30/2020",
207 | "value": 2400
208 | },
209 | {
210 | "date": "10/6/2020",
211 | "value": 2200
212 | },
213 | {
214 | "date": "10/8/2020",
215 | "value": 2450
216 | },
217 | {
218 | "date": "10/9/2020",
219 | "value": 2500
220 | },
221 | {
222 | "date": "10/14/2020",
223 | "value": 2100
224 | },
225 | {
226 | "date": "10/19/2020",
227 | "value": 2450
228 | },
229 | {
230 | "date": "10/21/2020",
231 | "value": 2200
232 | },
233 | {
234 | "date": "10/27/2020",
235 | "value": 2100
236 | },
237 | {
238 | "date": "10/29/2020",
239 | "value": 2350
240 | },
241 | {
242 | "date": "10/30/2020",
243 | "value": 2100
244 | },
245 | {
246 | "date": "11/3/2020",
247 | "value": 2300
248 | },
249 | {
250 | "date": "11/4/2020",
251 | "value": 2200
252 | },
253 | {
254 | "date": "11/6/2020",
255 | "value": 2350
256 | },
257 | {
258 | "date": "11/9/2020",
259 | "value": 2250
260 | },
261 | {
262 | "date": "11/13/2020",
263 | "value": 2400
264 | },
265 | {
266 | "date": "11/14/2020",
267 | "value": 2500
268 | },
269 | {
270 | "date": "11/16/2020",
271 | "value": 2400
272 | },
273 | {
274 | "date": "11/18/2020",
275 | "value": 2250
276 | },
277 | {
278 | "date": "11/20/2020",
279 | "value": 2100
280 | },
281 | {
282 | "date": "11/22/2020",
283 | "value": 2040
284 | },
285 | {
286 | "date": "11/24/2020",
287 | "value": 2500
288 | },
289 | {
290 | "date": "12/1/2020",
291 | "value": 2550
292 | },
293 | {
294 | "date": "12/5/2020",
295 | "value": 2200
296 | },
297 | {
298 | "date": "12/6/2020",
299 | "value": 2400
300 | },
301 | {
302 | "date": "12/8/2020",
303 | "value": 2100
304 | },
305 | {
306 | "date": "12/11/2020",
307 | "value": 2200
308 | },
309 | {
310 | "date": "12/12/2020",
311 | "value": 2400
312 | },
313 | {
314 | "date": "12/13/2020",
315 | "value": 2450
316 | },
317 | {
318 | "date": "12/14/2020",
319 | "value": 2250
320 | },
321 | {
322 | "date": "12/16/2020",
323 | "value": 2300
324 | },
325 | {
326 | "date": "12/18/2020",
327 | "value": 2400
328 | },
329 | {
330 | "date": "12/20/2020",
331 | "value": 2250
332 | },
333 | {
334 | "date": "12/22/2020",
335 | "value": 2200
336 | },
337 | {
338 | "date": "12/26/2020",
339 | "value": 2500
340 | },
341 | {
342 | "date": "12/27/2020",
343 | "value": 2000
344 | },
345 | {
346 | "date": "12/29/2020",
347 | "value": 2400
348 | }
349 | ]
--------------------------------------------------------------------------------
/src/data/tanyofish-swimming-2018.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "date": "1/6/2018",
4 | "value": 2700
5 | },
6 | {
7 | "date": "1/15/2018",
8 | "value": 2300
9 | },
10 | {
11 | "date": "1/18/2018",
12 | "value": 3700
13 | },
14 | {
15 | "date": "1/20/2018",
16 | "value": 2400
17 | },
18 | {
19 | "date": "1/27/2018",
20 | "value": 3000
21 | },
22 | {
23 | "date": "1/31/2018",
24 | "value": 2000
25 | },
26 | {
27 | "date": "2/3/2018",
28 | "value": 2400
29 | },
30 | {
31 | "date": "2/10/2018",
32 | "value": 2000
33 | },
34 | {
35 | "date": "2/17/2018",
36 | "value": 2400
37 | },
38 | {
39 | "date": "2/24/2018",
40 | "value": 2300
41 | },
42 | {
43 | "date": "3/10/2018",
44 | "value": 2300
45 | },
46 | {
47 | "date": "3/17/2018",
48 | "value": 2500
49 | },
50 | {
51 | "date": "3/19/2018",
52 | "value": 2500,
53 | "alt_unit": "m"
54 | },
55 | {
56 | "date": "3/21/2018",
57 | "value": 2500,
58 | "alt_unit": "m"
59 | },
60 | {
61 | "date": "3/28/2018",
62 | "value": 2500,
63 | "alt_unit": "m"
64 | },
65 | {
66 | "date": "3/31/2018",
67 | "value": 2400
68 | },
69 | {
70 | "date": "4/2/2018",
71 | "value": 2300,
72 | "alt_unit": "m"
73 | },
74 | {
75 | "date": "4/7/2018",
76 | "value": 2400
77 | },
78 | {
79 | "date": "4/14/2018",
80 | "value": 2500
81 | },
82 | {
83 | "date": "4/21/2018",
84 | "value": 2700
85 | },
86 | {
87 | "date": "4/28/2018",
88 | "value": 2400
89 | },
90 | {
91 | "date": "4/30/2018",
92 | "value": 2500,
93 | "alt_unit": "m"
94 | },
95 | {
96 | "date": "5/5/2018",
97 | "value": 2400
98 | },
99 | {
100 | "date": "5/12/2018",
101 | "value": 2500
102 | },
103 | {
104 | "date": "5/22/2018",
105 | "value": 2500
106 | },
107 | {
108 | "date": "5/25/2018",
109 | "value": 2200
110 | },
111 | {
112 | "date": "5/28/2018",
113 | "value": 2500
114 | },
115 | {
116 | "date": "6/2/2018",
117 | "value": 2200
118 | },
119 | {
120 | "date": "6/9/2018",
121 | "value": 2300
122 | },
123 | {
124 | "date": "6/16/2018",
125 | "value": 2600
126 | },
127 | {
128 | "date": "6/23/2018",
129 | "value": 2500
130 | },
131 | {
132 | "date": "7/5/2018",
133 | "value": 2500
134 | },
135 | {
136 | "date": "7/7/2018",
137 | "value": 2300
138 | },
139 | {
140 | "date": "7/11/2018",
141 | "value": 2400
142 | },
143 | {
144 | "date": "7/14/2018",
145 | "value": 2700
146 | },
147 | {
148 | "date": "7/18/2018",
149 | "value": 2500
150 | },
151 | {
152 | "date": "7/21/2018",
153 | "value": 2500
154 | },
155 | {
156 | "date": "7/28/2018",
157 | "value": 2400
158 | },
159 | {
160 | "date": "8/1/2018",
161 | "value": 2000
162 | },
163 | {
164 | "date": "8/3/2018",
165 | "value": 1800
166 | },
167 | {
168 | "date": "8/4/2018",
169 | "value": 2200
170 | },
171 | {
172 | "date": "8/5/2018",
173 | "value": 3000,
174 | "alt_unit": "m"
175 | },
176 | {
177 | "date": "8/11/2018",
178 | "value": 2500
179 | },
180 | {
181 | "date": "8/15/2018",
182 | "value": 2400
183 | },
184 | {
185 | "date": "8/18/2018",
186 | "value": 2200
187 | },
188 | {
189 | "date": "8/20/2018",
190 | "value": 2100
191 | },
192 | {
193 | "date": "8/25/2018",
194 | "value": 2300
195 | },
196 | {
197 | "date": "8/26/2018",
198 | "value": 3050,
199 | "alt_unit": "m"
200 | },
201 | {
202 | "date": "8/29/2018",
203 | "value": 2000
204 | },
205 | {
206 | "date": "9/1/2018",
207 | "value": 2200
208 | },
209 | {
210 | "date": "9/3/2018",
211 | "value": 2100
212 | },
213 | {
214 | "date": "9/5/2018",
215 | "value": 1900
216 | },
217 | {
218 | "date": "9/8/2018",
219 | "value": 2700
220 | },
221 | {
222 | "date": "9/9/2018",
223 | "value": 3250,
224 | "alt_unit": "m"
225 | },
226 | {
227 | "date": "9/15/2018",
228 | "value": 2400
229 | },
230 | {
231 | "date": "9/19/2018",
232 | "value": 1900
233 | },
234 | {
235 | "date": "9/22/2018",
236 | "value": 2700
237 | },
238 | {
239 | "date": "9/23/2018",
240 | "value": 3000,
241 | "alt_unit": "m"
242 | },
243 | {
244 | "date": "9/29/2018",
245 | "value": 2800
246 | },
247 | {
248 | "date": "10/6/2018",
249 | "value": 2400
250 | },
251 | {
252 | "date": "10/7/2018",
253 | "value": 3000,
254 | "alt_unit": "m"
255 | },
256 | {
257 | "date": "10/13/2018",
258 | "value": 2000
259 | },
260 | {
261 | "date": "10/17/2018",
262 | "value": 2300
263 | },
264 | {
265 | "date": "10/18/2018",
266 | "value": 2000,
267 | "alt_unit": "m"
268 | },
269 | {
270 | "date": "10/25/2018",
271 | "value": 3200,
272 | "alt_unit": "m"
273 | },
274 | {
275 | "date": "10/27/2018",
276 | "value": 2700
277 | },
278 | {
279 | "date": "10/28/2018",
280 | "value": 3300,
281 | "alt_unit": "m"
282 | },
283 | {
284 | "date": "11/3/2018",
285 | "value": 2500
286 | },
287 | {
288 | "date": "11/4/2018",
289 | "value": 2400,
290 | "alt_unit": "m"
291 | },
292 | {
293 | "date": "11/9/2018",
294 | "value": 2200
295 | },
296 | {
297 | "date": "11/21/2018",
298 | "value": 1700
299 | },
300 | {
301 | "date": "11/23/2018",
302 | "value": 2500
303 | },
304 | {
305 | "date": "12/1/2018",
306 | "value": 2200
307 | },
308 | {
309 | "date": "12/2/2018",
310 | "value": 3000,
311 | "alt_unit": "m"
312 | },
313 | {
314 | "date": "12/5/2018",
315 | "value": 2400
316 | },
317 | {
318 | "date": "12/8/2018",
319 | "value": 2200
320 | },
321 | {
322 | "date": "12/13/2018",
323 | "value": 2300
324 | },
325 | {
326 | "date": "12/15/2018",
327 | "value": 2000
328 | },
329 | {
330 | "date": "12/18/2018",
331 | "value": 2000
332 | },
333 | {
334 | "date": "12/22/2018",
335 | "value": 2000
336 | },
337 | {
338 | "date": "12/24/2018",
339 | "value": 2650
340 | },
341 | {
342 | "date": "12/27/2018",
343 | "value": 2500
344 | },
345 | {
346 | "date": "12/29/2018",
347 | "value": 2500
348 | },
349 | {
350 | "date": "12/31/2018",
351 | "value": 1900
352 | }
353 | ]
--------------------------------------------------------------------------------
/src/data/tanyoung-piano_practice-2019.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "date":"1/1/2019",
4 | "value":20
5 | },
6 | {
7 | "date":"1/2/2019",
8 | "value":28
9 | },
10 | {
11 | "date":"1/3/2019",
12 | "value":37
13 | },
14 | {
15 | "date":"1/4/2019",
16 | "value":18
17 | },
18 | {
19 | "date":"1/6/2019",
20 | "value":40
21 | },
22 | {
23 | "date":"1/8/2019",
24 | "value":15
25 | },
26 | {
27 | "date":"1/13/2019",
28 | "value":12
29 | },
30 | {
31 | "date":"1/16/2019",
32 | "value":34
33 | },
34 | {
35 | "date":"1/18/2019",
36 | "value":16
37 | },
38 | {
39 | "date":"1/21/2019",
40 | "value":29
41 | },
42 | {
43 | "date":"1/26/2019",
44 | "value":46
45 | },
46 | {
47 | "date":"1/29/2019",
48 | "value":1
49 | },
50 | {
51 | "date":"1/31/2019",
52 | "value":66
53 | },
54 | {
55 | "date":"2/1/2019",
56 | "value":36
57 | },
58 | {
59 | "date":"2/2/2019",
60 | "value":20
61 | },
62 | {
63 | "date":"2/4/2019",
64 | "value":38
65 | },
66 | {
67 | "date":"2/6/2019",
68 | "value":46
69 | },
70 | {
71 | "date":"2/8/2019",
72 | "value":48
73 | },
74 | {
75 | "date":"2/12/2019",
76 | "value":32
77 | },
78 | {
79 | "date":"2/13/2019",
80 | "value":4
81 | },
82 | {
83 | "date":"2/14/2019",
84 | "value":8
85 | },
86 | {
87 | "date":"3/8/2019",
88 | "value":15
89 | },
90 | {
91 | "date":"3/9/2019",
92 | "value":21
93 | },
94 | {
95 | "date":"3/14/2019",
96 | "value":11
97 | },
98 | {
99 | "date":"3/16/2019",
100 | "value":48
101 | },
102 | {
103 | "date":"3/17/2019",
104 | "value":36
105 | },
106 | {
107 | "date":"3/20/2019",
108 | "value":18
109 | },
110 | {
111 | "date":"3/21/2019",
112 | "value":48
113 | },
114 | {
115 | "date":"3/23/2019",
116 | "value":100
117 | },
118 | {
119 | "date":"3/24/2019",
120 | "value":22
121 | },
122 | {
123 | "date":"3/27/2019",
124 | "value":27
125 | },
126 | {
127 | "date":"3/28/2019",
128 | "value":47
129 | },
130 | {
131 | "date":"3/30/2019",
132 | "value":37
133 | },
134 | {
135 | "date":"3/31/2019",
136 | "value":74
137 | },
138 | {
139 | "date":"4/3/2019",
140 | "value":24
141 | },
142 | {
143 | "date":"4/6/2019",
144 | "value":66
145 | },
146 | {
147 | "date":"4/7/2019",
148 | "value":47
149 | },
150 | {
151 | "date":"4/8/2019",
152 | "value":65
153 | },
154 | {
155 | "date":"4/9/2019",
156 | "value":29
157 | },
158 | {
159 | "date":"4/10/2019",
160 | "value":30
161 | },
162 | {
163 | "date":"4/11/2019",
164 | "value":24
165 | },
166 | {
167 | "date":"4/12/2019",
168 | "value":31
169 | },
170 | {
171 | "date":"4/13/2019",
172 | "value":78
173 | },
174 | {
175 | "date":"4/14/2019",
176 | "value":156
177 | },
178 | {
179 | "date":"4/15/2019",
180 | "value":44
181 | },
182 | {
183 | "date":"4/16/2019",
184 | "value":39
185 | },
186 | {
187 | "date":"4/17/2019",
188 | "value":25
189 | },
190 | {
191 | "date":"4/18/2019",
192 | "value":13
193 | },
194 | {
195 | "date":"4/19/2019",
196 | "value":17
197 | },
198 | {
199 | "date":"4/20/2019",
200 | "value":34
201 | },
202 | {
203 | "date":"4/21/2019",
204 | "value":40
205 | },
206 | {
207 | "date":"4/22/2019",
208 | "value":27
209 | },
210 | {
211 | "date":"4/23/2019",
212 | "value":63
213 | },
214 | {
215 | "date":"4/24/2019",
216 | "value":19
217 | },
218 | {
219 | "date":"4/25/2019",
220 | "value":104
221 | },
222 | {
223 | "date":"4/26/2019",
224 | "value":13
225 | },
226 | {
227 | "date":"4/27/2019",
228 | "value":7
229 | },
230 | {
231 | "date":"4/28/2019",
232 | "value":24
233 | },
234 | {
235 | "date":"4/29/2019",
236 | "value":26
237 | },
238 | {
239 | "date":"4/30/2019",
240 | "value":27
241 | },
242 | {
243 | "date":"5/1/2019",
244 | "value":22
245 | },
246 | {
247 | "date":"5/2/2019",
248 | "value":88
249 | },
250 | {
251 | "date":"5/3/2019",
252 | "value":62
253 | },
254 | {
255 | "date":"5/4/2019",
256 | "value":7
257 | },
258 | {
259 | "date":"5/5/2019",
260 | "value":85
261 | },
262 | {
263 | "date":"5/6/2019",
264 | "value":50
265 | },
266 | {
267 | "date":"5/7/2019",
268 | "value":21
269 | },
270 | {
271 | "date":"5/8/2019",
272 | "value":3
273 | },
274 | {
275 | "date":"5/9/2019",
276 | "value":23
277 | },
278 | {
279 | "date":"5/11/2019",
280 | "value":69
281 | },
282 | {
283 | "date":"5/12/2019",
284 | "value":32
285 | },
286 | {
287 | "date":"5/14/2019",
288 | "value":15
289 | },
290 | {
291 | "date":"5/15/2019",
292 | "value":22
293 | },
294 | {
295 | "date":"5/16/2019",
296 | "value":22
297 | },
298 | {
299 | "date":"5/19/2019",
300 | "value":15
301 | },
302 | {
303 | "date":"5/21/2019",
304 | "value":35
305 | },
306 | {
307 | "date":"5/22/2019",
308 | "value":11
309 | },
310 | {
311 | "date":"5/26/2019",
312 | "value":16
313 | },
314 | {
315 | "date":"5/27/2019",
316 | "value":57
317 | },
318 | {
319 | "date":"5/28/2019",
320 | "value":45
321 | },
322 | {
323 | "date":"5/29/2019",
324 | "value":14
325 | },
326 | {
327 | "date":"5/30/2019",
328 | "value":30
329 | },
330 | {
331 | "date":"6/2/2019",
332 | "value":17
333 | },
334 | {
335 | "date":"6/4/2019",
336 | "value":17
337 | },
338 | {
339 | "date":"6/5/2019",
340 | "value":26
341 | },
342 | {
343 | "date":"6/7/2019",
344 | "value":9
345 | },
346 | {
347 | "date":"6/8/2019",
348 | "value":45
349 | },
350 | {
351 | "date":"6/9/2019",
352 | "value":47
353 | },
354 | {
355 | "date":"6/10/2019",
356 | "value":18
357 | },
358 | {
359 | "date":"6/11/2019",
360 | "value":19
361 | },
362 | {
363 | "date":"6/14/2019",
364 | "value":29
365 | },
366 | {
367 | "date":"6/15/2019",
368 | "value":29
369 | },
370 | {
371 | "date":"6/18/2019",
372 | "value":13
373 | },
374 | {
375 | "date":"6/25/2019",
376 | "value":13
377 | },
378 | {
379 | "date":"6/26/2019",
380 | "value":12
381 | },
382 | {
383 | "date":"6/28/2019",
384 | "value":9
385 | },
386 | {
387 | "date":"7/3/2019",
388 | "value":13
389 | },
390 | {
391 | "date":"7/5/2019",
392 | "value":30
393 | },
394 | {
395 | "date":"7/7/2019",
396 | "value":34
397 | },
398 | {
399 | "date":"7/9/2019",
400 | "value":33
401 | },
402 | {
403 | "date":"7/11/2019",
404 | "value":29
405 | },
406 | {
407 | "date":"7/12/2019",
408 | "value":3
409 | },
410 | {
411 | "date":"7/16/2019",
412 | "value":30
413 | },
414 | {
415 | "date":"7/17/2019",
416 | "value":3
417 | },
418 | {
419 | "date":"7/21/2019",
420 | "value":14
421 | },
422 | {
423 | "date":"7/25/2019",
424 | "value":18
425 | },
426 | {
427 | "date":"7/27/2019",
428 | "value":21
429 | },
430 | {
431 | "date":"8/4/2019",
432 | "value":22
433 | },
434 | {
435 | "date":"8/6/2019",
436 | "value":0
437 | },
438 | {
439 | "date":"8/14/2019",
440 | "value":11
441 | },
442 | {
443 | "date":"8/15/2019",
444 | "value":9
445 | },
446 | {
447 | "date":"8/26/2019",
448 | "value":13
449 | },
450 | {
451 | "date":"8/27/2019",
452 | "value":22
453 | },
454 | {
455 | "date":"9/10/2019",
456 | "value":4
457 | },
458 | {
459 | "date":"9/17/2019",
460 | "value":13
461 | },
462 | {
463 | "date":"9/24/2019",
464 | "value":4
465 | },
466 | {
467 | "date":"10/9/2019",
468 | "value":4
469 | },
470 | {
471 | "date":"10/29/2019",
472 | "value":13
473 | },
474 | {
475 | "date":"11/21/2019",
476 | "value":11
477 | },
478 | {
479 | "date":"11/23/2019",
480 | "value":7
481 | },
482 | {
483 | "date":"11/25/2019",
484 | "value":22
485 | }
486 | ]
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | .blue .author,
2 | .blue a {
3 | color: #031968;
4 | }
5 | .blue i {
6 | background-color: #031968;
7 | }
8 | .blue ii {
9 | background-color: #87ceeb;
10 | }
11 | .blue .text-highlight a {
12 | color: #87ceeb !important;
13 | }
14 | .red .author,
15 | .red a {
16 | color: darkred;
17 | }
18 | .red i {
19 | background-color: darkred;
20 | }
21 | .red ii {
22 | background-color: orange;
23 | }
24 | .red .text-highlight a {
25 | color: orange !important;
26 | }
27 | .green .author,
28 | .green a {
29 | color: darkgreen;
30 | }
31 | .green i {
32 | background-color: darkgreen;
33 | }
34 | .green ii {
35 | background-color: lightgreen;
36 | }
37 | .green .text-highlight a {
38 | color: lightgreen !important;
39 | }
40 | .teal .author,
41 | .teal a {
42 | color: Teal;
43 | }
44 | .teal i {
45 | background-color: Teal;
46 | }
47 | .teal ii {
48 | background-color: turquoise;
49 | }
50 | .teal .text-highlight a {
51 | color: turquoise !important;
52 | }
53 | .purple .author,
54 | .purple a {
55 | color: purple;
56 | }
57 | .purple i {
58 | background-color: purple;
59 | }
60 | .purple ii {
61 | background-color: coral;
62 | }
63 | .purple .text-highlight a {
64 | color: coral !important;
65 | }
66 | .brown .author,
67 | .brown a {
68 | color: Brown;
69 | }
70 | .brown i {
71 | background-color: Brown;
72 | }
73 | .brown ii {
74 | background-color: darkOrange;
75 | }
76 | .brown .text-highlight a {
77 | color: darkOrange !important;
78 | }
79 | .two-red .author,
80 | .two-red a {
81 | color: #d73027;
82 | }
83 | .two-red i {
84 | background-color: #d73027;
85 | }
86 | .two-red ii {
87 | background-color: #fc8d59;
88 | }
89 | .two-red .text-highlight a {
90 | color: #fc8d59 !important;
91 | }
92 | .two-blue .author,
93 | .two-blue a {
94 | color: #4575b4;
95 | }
96 | .two-blue i {
97 | background-color: #4575b4;
98 | }
99 | .two-blue ii {
100 | background-color: #91bfdb;
101 | }
102 | .two-blue .text-highlight a {
103 | color: #91bfdb !important;
104 | }
105 | body {
106 | margin: 0;
107 | padding: 0;
108 | color: #212529;
109 | }
110 | .hide {
111 | display: hide;
112 | }
113 | .show {
114 | display: block;
115 | }
116 | .show-inline {
117 | display: inline;
118 | }
119 | .header {
120 | padding-bottom: 36px;
121 | position: relative;
122 | }
123 | .header .author {
124 | font-size: 24px;
125 | }
126 | .header .topic {
127 | font-size: 42px;
128 | font-weight: bold;
129 | line-height: 48px;
130 | }
131 | .header-fixed {
132 | position: fixed;
133 | background-color: #212529;
134 | text-align: center;
135 | width: 100%;
136 | left: 0;
137 | top: 0;
138 | z-index: 1000;
139 | padding-top: 12px;
140 | padding-bottom: 12px;
141 | -webkit-box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.4);
142 | -moz-box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.4);
143 | box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.4);
144 | }
145 | .header-fixed .author,
146 | .header-fixed .topic {
147 | color: #fff !important;
148 | font-size: 16px;
149 | display: inline-block;
150 | }
151 | .header-fixed .author {
152 | margin-right: 8px;
153 | }
154 | .menu {
155 | position: relative;
156 | top: 0;
157 | right: 0;
158 | padding-top: 24px;
159 | width: 100%;
160 | z-index: 1000;
161 | text-align: right;
162 | }
163 | .menu .menu-text {
164 | margin-bottom: 8px;
165 | cursor: pointer;
166 | }
167 | .menu .menu-close {
168 | letter-spacing: 0.05em;
169 | }
170 | .menu .menu-content {
171 | display: none;
172 | background-color: #212529;
173 | position: fixed;
174 | top: 0;
175 | color: #fff;
176 | right: 0px;
177 | padding: 24px;
178 | text-align: left;
179 | height: 100%;
180 | }
181 | .menu .menu-content .block {
182 | padding-top: 20px;
183 | margin-top: 20px;
184 | border-top: 1px solid #495057;
185 | }
186 | .menu .menu-content .year {
187 | font-size: 12px;
188 | letter-spacing: 0.2em;
189 | margin-bottom: 12px;
190 | color: #ced4da;
191 | }
192 | .menu .menu-content .list {
193 | margin: 0;
194 | padding: 0;
195 | list-style: none;
196 | }
197 | .menu .menu-content .list li {
198 | margin-bottom: 8px;
199 | letter-spacing: 0.02em;
200 | }
201 | .menu .menu-content .list li:last-child {
202 | margin-bottom: 0px;
203 | }
204 | .menu .menu-content .list li.selected {
205 | color: #ced4da;
206 | }
207 | .menu .menu-content .list a {
208 | color: #fff;
209 | text-decoration: none;
210 | }
211 | .summary,
212 | .max,
213 | .stats,
214 | .byDay {
215 | padding-top: 24px;
216 | padding-bottom: 24px;
217 | font-weight: 500;
218 | font-size: 24px;
219 | line-height: 120%;
220 | }
221 | .summary {
222 | border-top: 1px solid #e9ecef;
223 | border-bottom: 1px solid #e9ecef;
224 | }
225 | .fixed {
226 | overflow-x: auto;
227 | }
228 | .slider {
229 | color: #868e96;
230 | padding: 8px;
231 | font-size: 16px;
232 | }
233 | .max,
234 | .stats {
235 | border-bottom: 1px solid #e9ecef;
236 | }
237 | .summary,
238 | .stats,
239 | .footer {
240 | background-color: #f8f9fa;
241 | }
242 | .unit-selection {
243 | padding-top: 36px;
244 | padding-bottom: 24px;
245 | font-weight: 500;
246 | font-size: 18px;
247 | margin-bottom: -12px;
248 | }
249 | .unit-selection .title {
250 | font-size: 24px;
251 | padding-bottom: 12px;
252 | }
253 | .unit-selection .input {
254 | display: inline-block;
255 | margin-right: 16px;
256 | }
257 | .unit-selection .input:last-child {
258 | margin-right: 0;
259 | }
260 | .unit-selection input {
261 | margin-right: 8px;
262 | margin-left: 16px;
263 | }
264 | .unit-selection input:first-child {
265 | margin-left: 0;
266 | }
267 | .legend {
268 | line-height: 90%;
269 | padding-top: 12px;
270 | }
271 | .legend .block {
272 | font-size: 1px;
273 | display: inline-block;
274 | }
275 | .legend .label {
276 | font-size: 12px;
277 | text-align: center;
278 | color: #212529;
279 | font-weight: normal;
280 | display: inline-block;
281 | }
282 | .radios {
283 | text-align: right;
284 | }
285 | .highlight {
286 | font-style: normal;
287 | font-weight: normal;
288 | padding: 0 8px;
289 | }
290 | i {
291 | font-style: normal;
292 | font-weight: normal;
293 | padding: 0 8px;
294 | color: #fff;
295 | display: inline-block;
296 | margin-top: 4px;
297 | margin-bottom: 4px;
298 | }
299 | ii {
300 | font-style: normal;
301 | font-weight: normal;
302 | padding: 0 8px;
303 | display: inline-block;
304 | margin-top: 4px;
305 | margin-bottom: 4px;
306 | }
307 | l {
308 | font-weight: 200;
309 | }
310 | .footer {
311 | font-size: 16px;
312 | margin-top: 36px;
313 | padding-top: 24px;
314 | padding-bottom: 24px;
315 | border-top: 1px solid #e9ecef;
316 | color: #868e96;
317 | }
318 | .footer .link {
319 | margin-right: 16px;
320 | padding-right: 16px;
321 | border-right: 1px solid #868e96;
322 | }
323 | .footer .link:last-child {
324 | margin-right: 0;
325 | padding-right: 0;
326 | border-right: none;
327 | }
328 | .footer .link a {
329 | margin-right: 6px;
330 | }
331 | .footer .link a:first-child {
332 | margin-left: 6px;
333 | }
334 | .footer .link a:last-child {
335 | margin-right: 0;
336 | }
337 | /* Medium devices (desktops, 992px and up) */
338 | @media (min-width: 992px) {
339 | .legend {
340 | text-align: right;
341 | padding-top: 0;
342 | }
343 | .menu-content {
344 | position: absolute !important;
345 | top: unset !important;
346 | height: unset !important;
347 | }
348 | .menu-content .block:first-child {
349 | border-top: none;
350 | padding-top: 0;
351 | margin-top: 0;
352 | }
353 | .menu-close {
354 | display: none;
355 | }
356 | }
357 | text {
358 | -webkit-user-select: none;
359 | /* Chrome all / Safari all */
360 | -moz-user-select: none;
361 | /* Firefox all */
362 | -ms-user-select: none;
363 | /* IE 10+ */
364 | user-select: none;
365 | cursor: default;
366 | }
367 | .block:hover {
368 | stroke: #212529;
369 | stroke-width: 1px;
370 | }
371 | .lines {
372 | stroke: #ced4da;
373 | }
374 | .month-path {
375 | stroke: #212529;
376 | stroke-width: 1.5px;
377 | shape-rendering: crispEdges;
378 | fill: none;
379 | }
380 | .month-text {
381 | font-size: 14px;
382 | alignment-baseline: hanging;
383 | }
384 | .day-text {
385 | font-size: 14px;
386 | alignment-baseline: central;
387 | text-anchor: end;
388 | }
389 | .label-text {
390 | font-size: 14px;
391 | alignment-baseline: central;
392 | }
393 | .axis path {
394 | stroke: none;
395 | }
396 | .tick line {
397 | stroke: rgba(33, 37, 41, 0.2);
398 | }
399 | .tick text {
400 | font-size: 12px;
401 | }
402 | .bg {
403 | fill: #212529;
404 | }
405 | .tp {
406 | font-weight: normal;
407 | font-size: 14px;
408 | fill: #fff;
409 | }
410 |
--------------------------------------------------------------------------------
/src/processors/analysis.js:
--------------------------------------------------------------------------------
1 | import moment from 'moment';
2 | import { locale, humanizeUnitId, humanizeDuration } from './formats';
3 |
4 | const getConvertedData = (data, conversion, decimal) => {
5 | let newData = [];
6 | for (const d of data) {
7 | let {date, value, alt_unit} = d;
8 | const newVal = {date, value};
9 | if (alt_unit != null) {
10 | newVal.altValue = value;
11 | let converted = value * conversion;
12 | if (decimal != null) {
13 | converted = Math.round(converted * Math.pow(10, decimal)) / Math.pow(10, decimal);
14 | } else {
15 | converted = Math.round(converted);
16 | }
17 | newVal.value = converted;
18 |
19 | }
20 | newData.push(newVal);
21 | }
22 | return newData
23 | }
24 |
25 | const arrToObj = (arr) => {
26 | return arr.reduce((obj, pair) => {
27 | obj[pair[0]] = pair[1];
28 | return obj;
29 | }, {});
30 | }
31 |
32 | const getSum = (data) => {
33 | return data.map(d => d.value).reduce((accumulator, memo) => accumulator + memo, 0);
34 | }
35 |
36 | const getNumberOfDaysInYear = (year) => {
37 | return year % 400 === 0 || (year % 100 !== 0 && year % 4 === 0) ? 366 : 365;
38 | }
39 |
40 | const getAverages = (sum, daysCount, year) => {
41 | return {
42 | day: locale(sum / daysCount),
43 | week: locale(sum / getNumberOfDaysInYear(year) * 7),
44 | month: locale(sum / 12),
45 | };
46 | }
47 |
48 | const getWeek = (date) =>{
49 | const md = moment(date, 'M/D/YYYY');
50 | let wId = md.week();
51 | if (wId === 1 && md.month() === 11) {
52 | wId = md.add(-7, 'days').week() + 1;
53 | }
54 | return wId;
55 | }
56 |
57 | const mapDataByUnit = (data, year) => {
58 | //first day, week, month = 0
59 | const byDay = arrToObj(data.map(d =>[moment(d.date, 'M/D/YYYY').dayOfYear() - 1, d.value]));
60 | let byUnit = {
61 | day: byDay,
62 | week: {},
63 | month: {}
64 | };
65 |
66 | for (const i in data) {
67 | const d = data[i];
68 | //week
69 | let w = getWeek(d.date) - 1;
70 | if (+i === 0) {
71 | byUnit.week[w] = d.value;
72 | } else if (getWeek(d.date) > getWeek(data[+i - 1].date)) {
73 | byUnit.week[w] = d.value;
74 | } else {
75 | byUnit.week[w] += d.value;
76 | }
77 | //month
78 | let m = moment(d.date, 'M/D/YYYY').month();
79 | if (+i === 0) {
80 | byUnit.month[m] = d.value;
81 | } else if (moment(d.date, 'M/D/YYYY').month() > moment(data[i - 1].date, 'M/D/YYYY').month()) {
82 | byUnit.month[m] = d.value;
83 | } else {
84 | byUnit.month[m] += d.value;
85 | }
86 | }
87 | return byUnit;
88 | }
89 |
90 | const getTotalCount = (year) => {
91 | return {
92 | day: getNumberOfDaysInYear(year),
93 | week: moment(year, 'YYYY').weeksInYear(),
94 | month: 12
95 | };
96 | }
97 |
98 | const getValueRange = (min, max, hasNegative) => {
99 | let newMax = max;
100 | // if values include negative, find a bigger abs
101 | if (hasNegative && min * -1 > max) {
102 | newMax = min * -1;
103 |
104 | }
105 | //get chroma range: brew colors upto 7 or 8
106 | const minDiff = Math.floor((newMax - min) / 8).toString();
107 | //steps increase 1, 2, 5, 10, 20, 50, 100, 200, 5000, 1000 ...
108 | let step = 10;
109 | const firstDigit = parseInt(minDiff[0], 0);
110 | if (firstDigit === 0) {
111 | step = 1;
112 | } else if (firstDigit < 2) {
113 | step = 2;
114 | } else if (firstDigit < 5) {
115 | step = 5;
116 | }
117 | const distance = step * Math.pow(10, (minDiff.length - 1));
118 |
119 | //color step values
120 | let currentStep = 0;
121 | let steps = [];
122 | do {
123 | if (currentStep + distance > min) {
124 | steps.push(currentStep);
125 | }
126 | currentStep += distance;
127 | }
128 | while (currentStep < newMax + distance);
129 |
130 | //if negative numbers, add mirrored negative numbers up front
131 | if (hasNegative) {
132 | const stepCount = steps.length;
133 | const dup = steps.slice(0);
134 | for (let i = 1; i < stepCount; i++) {
135 | dup.unshift(steps[i] * -1);
136 | }
137 | steps = dup;
138 | }
139 |
140 | return {min, max: newMax, steps, distance};
141 | }
142 |
143 | const getFence = (data) => {
144 | const sorted = data.sort((a, b) => a - b);
145 | const lowerQIdx = Math.round(data.length / 4);
146 | const upperQIdx = Math.round(data.length / 4 * 3);
147 | const interQRange = sorted[upperQIdx] - sorted[lowerQIdx];
148 | const innerFence = [
149 | sorted[lowerQIdx] - interQRange * 1.5,
150 | sorted[upperQIdx] + interQRange * 1.5,
151 | ];
152 | const outerFence = [
153 | sorted[lowerQIdx] - interQRange * 3,
154 | sorted[upperQIdx] + interQRange * 3,
155 | ];
156 | const outOfInnerFence = data.filter(d => d < outerFence[0] || d > innerFence[1]);
157 | // do not make too many outliers
158 | if (outOfInnerFence.length < Math.sqrt(data.length / 5)) {
159 | return innerFence;
160 | } else {
161 | return outerFence;
162 | }
163 | }
164 |
165 | const getCalendar = (data, year, hasNegative, isReverse) => {
166 | const byUnit = mapDataByUnit(data, year);
167 | const total = getTotalCount(year);
168 |
169 | const units = ['day', 'week', 'month'];
170 | const byUnitArray = units.map(unit => Object.entries(byUnit[unit]).map(d => d[1]));
171 |
172 | // get max vals and range by unit
173 | const maxByUnit = {};
174 | const rangeByUnit = {};
175 | for (const i in units) {
176 | const unit = units[i];
177 | const unitData = byUnit[unit];
178 | const maxVal = Math.max(...byUnitArray[i]);
179 | const minVal = Math.min(...byUnitArray[i]);
180 |
181 | // if negative number has in fact better meaning, get minimal data
182 | const trueMaxVal = isReverse ? minVal : maxVal;
183 |
184 | let unitWithMax = [];
185 | for (const j in unitData) {
186 | if (unitData[j] === trueMaxVal) {
187 | unitWithMax.push(humanizeUnitId(year, unit, j));
188 | }
189 | }
190 | maxByUnit[unit] = {val: trueMaxVal, list: unitWithMax};
191 |
192 | // get ranges that excludes outliers
193 | const outerFence = getFence(byUnitArray[i]);
194 |
195 | rangeByUnit[unit] = getValueRange(
196 | Math.max(minVal, outerFence[0]),
197 | Math.min(maxVal, outerFence[1]),
198 | hasNegative,
199 | );
200 | }
201 |
202 | return {byUnit, total, max: maxByUnit, range: rangeByUnit};
203 | }
204 |
205 | const getStatsByUnit = (data, year) => {
206 | const byUnit = mapDataByUnit(data, year);
207 | const units = ['day', 'week', 'month'];
208 | const total = getTotalCount(year);
209 | const active = {
210 | day: data.length,
211 | week: Object.keys(byUnit.week).length,
212 | month:Object.keys(byUnit.month).length,
213 | };
214 |
215 | //get the list conscutive day/week/month first
216 | const consecutive = arrToObj(units.map(unit => [unit, {active: [], inactive: []}]));
217 |
218 | for (const unit of units) {
219 | let prevStatus = byUnit[unit][0] != null ? 'active' : 'inactive';
220 | consecutive[unit][prevStatus][0] = {count: 1, start: 0};
221 | consecutive[unit][prevStatus === 'active' ? 'inactive' : 'active'][0] = {count: 0, start: null};
222 | for (let i = 0; i < total[unit]; i++) {
223 | if (i > 0) {
224 | let status = byUnit[unit][i] != null ? 'active' : 'inactive';
225 | //check with the previous value; same value -> incrase count, diff -> add new array
226 | if (status === prevStatus) {
227 | const len = consecutive[unit][status].length;
228 | consecutive[unit][status][len - 1].count++;
229 | } else {
230 | consecutive[unit][status].push({count: 1, start: i});
231 | }
232 | prevStatus = status;
233 | }
234 | };
235 | }
236 |
237 | //get max vals
238 | const consec = arrToObj(units.map(unit => {
239 | const maxCount = arrToObj(['active', 'inactive'].map(status =>
240 | [status, Math.max(...consecutive[unit][status].map(val => val.count))]
241 | ));
242 | const maxStarts = arrToObj(['active', 'inactive'].map((status, i) =>{
243 | const filtered = consecutive[unit][status].filter(val => {
244 | return val.count === maxCount[status];
245 | });
246 | const count = maxCount[status];
247 | return [status, {
248 | list: filtered.map(val => humanizeDuration(year, unit, val.start, count)),
249 | count
250 | }];
251 | }));
252 | return [unit, maxStarts];
253 | }));
254 |
255 | return { total, active, consec };
256 | }
257 |
258 | const getDataByDay = (data) => {
259 | return [...Array(7).keys()].map(day => {
260 | const dateInDay = data.filter(d => moment(d.date, 'M/D/YYYY').day() === day);
261 | return {
262 | freq: dateInDay.length,
263 | value: getSum(dateInDay),
264 | };
265 | });
266 | }
267 |
268 | export {getConvertedData, getSum, getAverages, getWeek, getCalendar, getStatsByUnit, getDataByDay};
269 |
--------------------------------------------------------------------------------
/src/data/tanyofish-swimming-2022.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "date":"1/1/2022",
4 | "value":3533.33
5 | },
6 | {
7 | "date":"1/2/2022",
8 | "value":2633.33
9 | },
10 | {
11 | "date":"1/7/2022",
12 | "value":3633.33
13 | },
14 | {
15 | "date":"1/9/2022",
16 | "value":3733.33
17 | },
18 | {
19 | "date":"1/10/2022",
20 | "value":2200
21 | },
22 | {
23 | "date":"1/12/2022",
24 | "value":2466.66
25 | },
26 | {
27 | "date":"1/16/2022",
28 | "value":3633.33
29 | },
30 | {
31 | "date":"1/23/2022",
32 | "value":3166.67
33 | },
34 | {
35 | "date":"1/24/2022",
36 | "value":2433.33
37 | },
38 | {
39 | "date":"2/3/2022",
40 | "value":2766.67
41 | },
42 | {
43 | "date":"2/5/2022",
44 | "value":3033.33
45 | },
46 | {
47 | "date":"2/10/2022",
48 | "value":3000
49 | },
50 | {
51 | "date":"2/11/2022",
52 | "value":2433.33
53 | },
54 | {
55 | "date":"2/13/2022",
56 | "value":3900
57 | },
58 | {
59 | "date":"2/15/2022",
60 | "value":2166.67
61 | },
62 | {
63 | "date":"2/17/2022",
64 | "value":2966.67
65 | },
66 | {
67 | "date":"2/18/2022",
68 | "value":2766.67
69 | },
70 | {
71 | "date":"2/23/2022",
72 | "value":2133.33
73 | },
74 | {
75 | "date":"3/1/2022",
76 | "value":2266.67
77 | },
78 | {
79 | "date":"3/5/2022",
80 | "value":1966.67
81 | },
82 | {
83 | "date":"3/6/2022",
84 | "value":2166.67
85 | },
86 | {
87 | "date":"3/13/2022",
88 | "value":2466.67
89 | },
90 | {
91 | "date":"3/15/2022",
92 | "value":2266.67
93 | },
94 | {
95 | "date":"3/16/2022",
96 | "value":2033.33
97 | },
98 | {
99 | "date":"3/18/2022",
100 | "value":2600
101 | },
102 | {
103 | "date":"3/22/2022",
104 | "value":1966.67
105 | },
106 | {
107 | "date":"3/24/2022",
108 | "value":3433.33
109 | },
110 | {
111 | "date":"3/25/2022",
112 | "value":3500
113 | },
114 | {
115 | "date":"3/27/2022",
116 | "value":2200
117 | },
118 | {
119 | "date":"3/29/2022",
120 | "value":2166.67
121 | },
122 | {
123 | "date":"3/31/2022",
124 | "value":3466.67
125 | },
126 | {
127 | "date":"4/2/2022",
128 | "value":2366.67
129 | },
130 | {
131 | "date":"4/5/2022",
132 | "value":2233.33
133 | },
134 | {
135 | "date":"4/10/2022",
136 | "value":2600
137 | },
138 | {
139 | "date":"4/11/2022",
140 | "value":2500
141 | },
142 | {
143 | "date":"4/12/2022",
144 | "value":2400
145 | },
146 | {
147 | "date":"4/14/2022",
148 | "value":3700
149 | },
150 | {
151 | "date":"4/16/2022",
152 | "value":2333.33
153 | },
154 | {
155 | "date":"4/17/2022",
156 | "value":1933.33
157 | },
158 | {
159 | "date":"4/20/2022",
160 | "value":2400.0
161 | },
162 | {
163 | "date":"4/21/2022",
164 | "value":3000
165 | },
166 | {
167 | "date":"4/23/2022",
168 | "value":2600
169 | },
170 | {
171 | "date":"4/28/2022",
172 | "value":3533.33
173 | },
174 | {
175 | "date":"5/1/2022",
176 | "value":3233.33
177 | },
178 | {
179 | "date":"5/5/2022",
180 | "value":3066.67
181 | },
182 | {
183 | "date":"5/7/2022",
184 | "value":2833.33
185 | },
186 | {
187 | "date":"5/8/2022",
188 | "value":3000
189 | },
190 | {
191 | "date":"5/10/2022",
192 | "value":2100
193 | },
194 | {
195 | "date":"5/12/2022",
196 | "value":2800
197 | },
198 | {
199 | "date":"5/14/2022",
200 | "value":2300
201 | },
202 | {
203 | "date":"5/15/2022",
204 | "value":3633.33
205 | },
206 | {
207 | "date":"5/17/2022",
208 | "value":2366.67
209 | },
210 | {
211 | "date":"5/19/2022",
212 | "value":2066.67
213 | },
214 | {
215 | "date":"5/21/2022",
216 | "value":2866.67
217 | },
218 | {
219 | "date":"5/22/2022",
220 | "value":3533.33
221 | },
222 | {
223 | "date":"5/26/2022",
224 | "value":2100
225 | },
226 | {
227 | "date":"5/29/2022",
228 | "value":2866.67
229 | },
230 | {
231 | "date":"5/30/2022",
232 | "value":2766.67
233 | },
234 | {
235 | "date":"5/31/2022",
236 | "value":2000
237 | },
238 | {
239 | "date":"6/2/2022",
240 | "value":1733.33
241 | },
242 | {
243 | "date":"6/4/2022",
244 | "value":3600
245 | },
246 | {
247 | "date":"6/5/2022",
248 | "value":3000
249 | },
250 | {
251 | "date":"6/7/2022",
252 | "value":2366.67
253 | },
254 | {
255 | "date":"6/9/2022",
256 | "value":2466.67
257 | },
258 | {
259 | "date":"6/12/2022",
260 | "value":3700
261 | },
262 | {
263 | "date":"6/14/2022",
264 | "value":2566.67
265 | },
266 | {
267 | "date":"6/16/2022",
268 | "value":1833.33
269 | },
270 | {
271 | "date":"6/21/2022",
272 | "value":2400
273 | },
274 | {
275 | "date":"6/23/2022",
276 | "value":2400
277 | },
278 | {
279 | "date":"7/2/2022",
280 | "value":1633.33
281 | },
282 | {
283 | "date":"7/3/2022",
284 | "value":3966.67
285 | },
286 | {
287 | "date":"7/7/2022",
288 | "value":2233.33
289 | },
290 | {
291 | "date":"7/9/2022",
292 | "value":2333.33
293 | },
294 | {
295 | "date":"7/10/2022",
296 | "value":2333.33
297 | },
298 | {
299 | "date":"7/12/2022",
300 | "value":2466.67
301 | },
302 | {
303 | "date":"7/14/2022",
304 | "value":2400
305 | },
306 | {
307 | "date":"7/16/2022",
308 | "value":3233.33
309 | },
310 | {
311 | "date":"7/17/2022",
312 | "value":2433.33
313 | },
314 | {
315 | "date":"7/24/2022",
316 | "value":3500
317 | },
318 | {
319 | "date":"7/26/2022",
320 | "value":1700
321 | },
322 | {
323 | "date":"7/28/2022",
324 | "value":2533.33
325 | },
326 | {
327 | "date":"7/29/2022",
328 | "value":2933.33
329 | },
330 | {
331 | "date":"7/31/2022",
332 | "value":2866.67
333 | },
334 | {
335 | "date":"8/2/2022",
336 | "value":2266.67
337 | },
338 | {
339 | "date":"8/4/2022",
340 | "value":1633.33
341 | },
342 | {
343 | "date":"8/6/2022",
344 | "value":2800
345 | },
346 | {
347 | "date":"8/7/2022",
348 | "value":2300
349 | },
350 | {
351 | "date":"8/11/2022",
352 | "value":2666.67
353 | },
354 | {
355 | "date":"8/14/2022",
356 | "value":3400
357 | },
358 | {
359 | "date":"8/16/2022",
360 | "value":1866.67
361 | },
362 | {
363 | "date":"8/18/2022",
364 | "value":2300
365 | },
366 | {
367 | "date":"8/20/2022",
368 | "value":2466.67
369 | },
370 | {
371 | "date":"8/21/2022",
372 | "value":3166.67
373 | },
374 | {
375 | "date":"8/25/2022",
376 | "value":2333.33
377 | },
378 | {
379 | "date":"9/15/2022",
380 | "value":2166.67
381 | },
382 | {
383 | "date":"9/16/2022",
384 | "value":2233.33
385 | },
386 | {
387 | "date":"9/19/2022",
388 | "value":2133.33
389 | },
390 | {
391 | "date":"9/21/2022",
392 | "value":2500
393 | },
394 | {
395 | "date":"9/24/2022",
396 | "value":2666.67
397 | },
398 | {
399 | "date":"9/25/2022",
400 | "value":3166.67
401 | },
402 | {
403 | "date":"9/27/2022",
404 | "value":2633.33
405 | },
406 | {
407 | "date":"9/29/2022",
408 | "value":2600
409 | },
410 | {
411 | "date":"10/1/2022",
412 | "value":2366.67
413 | },
414 | {
415 | "date":"10/3/2022",
416 | "value":2833.33
417 | },
418 | {
419 | "date":"10/8/2022",
420 | "value":1900
421 | },
422 | {
423 | "date":"10/9/2022",
424 | "value":3133.33
425 | },
426 | {
427 | "date":"10/12/2022",
428 | "value":2633.33
429 | },
430 | {
431 | "date":"10/16/2022",
432 | "value":3433.33
433 | },
434 | {
435 | "date":"10/21/2022",
436 | "value":2933.33
437 | },
438 | {
439 | "date":"10/23/2022",
440 | "value":2900
441 | },
442 | {
443 | "date":"10/29/2022",
444 | "value":3700
445 | },
446 | {
447 | "date":"10/31/2022",
448 | "value":2333.33
449 | },
450 | {
451 | "date":"11/5/2022",
452 | "value":3733.33
453 | },
454 | {
455 | "date":"11/6/2022",
456 | "value":3666.67
457 | },
458 | {
459 | "date":"11/13/2022",
460 | "value":443.83
461 | },
462 | {
463 | "date":"11/14/2022",
464 | "value":513.34
465 | },
466 | {
467 | "date":"11/15/2022",
468 | "value":5171.56
469 | },
470 | {
471 | "date":"11/16/2022",
472 | "value":4077.3
473 | },
474 | {
475 | "date":"11/17/2022",
476 | "value":4750.58
477 | },
478 | {
479 | "date":"11/18/2022",
480 | "value":1187.87
481 | },
482 | {
483 | "date":"11/19/2022",
484 | "value":1333.57
485 | },
486 | {
487 | "date":"11/20/2022",
488 | "value":402.1
489 | },
490 | {
491 | "date":"11/21/2022",
492 | "value":1581.58
493 | },
494 | {
495 | "date":"11/22/2022",
496 | "value":1231.67
497 | },
498 | {
499 | "date":"11/27/2022",
500 | "value":2566.67
501 | },
502 | {
503 | "date":"11/29/2022",
504 | "value":2500
505 | },
506 | {
507 | "date":"11/30/2022",
508 | "value":2433.33
509 | },
510 | {
511 | "date":"12/4/2022",
512 | "value":3866.67
513 | },
514 | {
515 | "date":"12/11/2022",
516 | "value":3166.67
517 | },
518 | {
519 | "date":"12/20/2022",
520 | "value":2500
521 | },
522 | {
523 | "date":"12/24/2022",
524 | "value":3300
525 | }
526 | ]
--------------------------------------------------------------------------------
/src/data/tanyofish-swimming-2019.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "date": "1/3/2019",
4 | "value": 2050
5 | },
6 | {
7 | "date": "1/5/2019",
8 | "value": 2600
9 | },
10 | {
11 | "date": "1/8/2019",
12 | "value": 2400
13 | },
14 | {
15 | "date": "1/13/2019",
16 | "value": 3000,
17 | "alt_unit": "m"
18 | },
19 | {
20 | "date": "1/19/2019",
21 | "value": 2200
22 | },
23 | {
24 | "date": "1/21/2019",
25 | "value": 2500
26 | },
27 | {
28 | "date": "1/26/2019",
29 | "value": 2300
30 | },
31 | {
32 | "date": "2/9/2019",
33 | "value": 2500
34 | },
35 | {
36 | "date": "2/14/2019",
37 | "value": 2000
38 | },
39 | {
40 | "date": "2/19/2019",
41 | "value": 2500,
42 | "alt_unit": "m"
43 | },
44 | {
45 | "date": "2/20/2019",
46 | "value": 3000,
47 | "alt_unit": "m"
48 | },
49 | {
50 | "date": "2/21/2019",
51 | "value": 2800,
52 | "alt_unit": "m"
53 | },
54 | {
55 | "date": "2/25/2019",
56 | "value": 2000,
57 | "alt_unit": "m"
58 | },
59 | {
60 | "date": "3/1/2019",
61 | "value": 1500,
62 | "alt_unit": "m"
63 | },
64 | {
65 | "date": "3/16/2019",
66 | "value": 1600
67 | },
68 | {
69 | "date": "3/20/2019",
70 | "value": 2000
71 | },
72 | {
73 | "date": "3/23/2019",
74 | "value": 2500
75 | },
76 | {
77 | "date": "3/30/2019",
78 | "value": 2800
79 | },
80 | {
81 | "date": "4/6/2019",
82 | "value": 2000
83 | },
84 | {
85 | "date": "4/7/2019",
86 | "value": 3000,
87 | "alt_unit": "m"
88 | },
89 | {
90 | "date": "4/10/2019",
91 | "value": 2100
92 | },
93 | {
94 | "date": "4/12/2019",
95 | "value": 1900
96 | },
97 | {
98 | "date": "4/13/2019",
99 | "value": 2600
100 | },
101 | {
102 | "date": "4/20/2019",
103 | "value": 2500
104 | },
105 | {
106 | "date": "4/27/2019",
107 | "value": 2300
108 | },
109 | {
110 | "date": "5/2/2019",
111 | "value": 2200
112 | },
113 | {
114 | "date": "5/4/2019",
115 | "value": 2300
116 | },
117 | {
118 | "date": "5/5/2019",
119 | "value": 2800,
120 | "alt_unit": "m"
121 | },
122 | {
123 | "date": "5/8/2019",
124 | "value": 2000
125 | },
126 | {
127 | "date": "5/11/2019",
128 | "value": 2100
129 | },
130 | {
131 | "date": "5/14/2019",
132 | "value": 2600
133 | },
134 | {
135 | "date": "5/18/2019",
136 | "value": 3000
137 | },
138 | {
139 | "date": "5/25/2019",
140 | "value": 2200
141 | },
142 | {
143 | "date": "5/27/2019",
144 | "value": 3000
145 | },
146 | {
147 | "date": "6/1/2019",
148 | "value": 2400
149 | },
150 | {
151 | "date": "6/2/2019",
152 | "value": 3000,
153 | "alt_unit": "m"
154 | },
155 | {
156 | "date": "6/6/2019",
157 | "value": 3100
158 | },
159 | {
160 | "date": "6/9/2019",
161 | "value": 2800
162 | },
163 | {
164 | "date": "6/10/2019",
165 | "value": 2300
166 | },
167 | {
168 | "date": "6/14/2019",
169 | "value": 2300
170 | },
171 | {
172 | "date": "6/15/2019",
173 | "value": 2200
174 | },
175 | {
176 | "date": "6/16/2019",
177 | "value": 2300,
178 | "alt_unit": "m"
179 | },
180 | {
181 | "date": "6/22/2019",
182 | "value": 2100
183 | },
184 | {
185 | "date": "6/26/2019",
186 | "value": 2000
187 | },
188 | {
189 | "date": "7/3/2019",
190 | "value": 2000
191 | },
192 | {
193 | "date": "7/4/2019",
194 | "value": 3100
195 | },
196 | {
197 | "date": "7/5/2019",
198 | "value": 2100
199 | },
200 | {
201 | "date": "7/6/2019",
202 | "value": 2200
203 | },
204 | {
205 | "date": "7/11/2019",
206 | "value": 2300
207 | },
208 | {
209 | "date": "7/18/2019",
210 | "value": 2450
211 | },
212 | {
213 | "date": "7/20/2019",
214 | "value": 2400
215 | },
216 | {
217 | "date": "7/27/2019",
218 | "value": 2500
219 | },
220 | {
221 | "date": "7/28/2019",
222 | "value": 3000,
223 | "alt_unit": "m"
224 | },
225 | {
226 | "date": "8/1/2019",
227 | "value": 2700
228 | },
229 | {
230 | "date": "8/3/2019",
231 | "value": 2500
232 | },
233 | {
234 | "date": "8/4/2019",
235 | "value": 2700,
236 | "alt_unit": "m"
237 | },
238 | {
239 | "date": "8/8/2019",
240 | "value": 2300
241 | },
242 | {
243 | "date": "8/15/2019",
244 | "value": 2100
245 | },
246 | {
247 | "date": "8/18/2019",
248 | "value": 3000,
249 | "alt_unit": "m"
250 | },
251 | {
252 | "date": "8/20/2019",
253 | "value": 2100
254 | },
255 | {
256 | "date": "8/22/2019",
257 | "value": 2100
258 | },
259 | {
260 | "date": "8/24/2019",
261 | "value": 2700
262 | },
263 | {
264 | "date": "8/29/2019",
265 | "value": 2200
266 | },
267 | {
268 | "date": "8/31/2019",
269 | "value": 3000
270 | },
271 | {
272 | "date": "9/12/2019",
273 | "value": 2400
274 | },
275 | {
276 | "date": "9/14/2019",
277 | "value": 2300
278 | },
279 | {
280 | "date": "9/19/2019",
281 | "value": 1500
282 | },
283 | {
284 | "date": "9/21/2019",
285 | "value": 2200
286 | },
287 | {
288 | "date": "9/22/2019",
289 | "value": 3000,
290 | "alt_unit": "m"
291 | },
292 | {
293 | "date": "9/26/2019",
294 | "value": 2500
295 | },
296 | {
297 | "date": "10/1/2019",
298 | "value": 2800
299 | },
300 | {
301 | "date": "10/3/2019",
302 | "value": 2200
303 | },
304 | {
305 | "date": "10/5/2019",
306 | "value": 2700
307 | },
308 | {
309 | "date": "10/8/2019",
310 | "value": 2500
311 | },
312 | {
313 | "date": "10/12/2019",
314 | "value": 2100
315 | },
316 | {
317 | "date": "10/15/2019",
318 | "value": 2200
319 | },
320 | {
321 | "date": "10/17/2019",
322 | "value": 2400
323 | },
324 | {
325 | "date": "10/21/2019",
326 | "value": 2600,
327 | "alt_unit": "m"
328 | },
329 | {
330 | "date": "10/23/2019",
331 | "value": 3000,
332 | "alt_unit": "m"
333 | },
334 | {
335 | "date": "10/26/2019",
336 | "value": 3000,
337 | "alt_unit": "m"
338 | },
339 | {
340 | "date": "10/27/2019",
341 | "value": 2600,
342 | "alt_unit": "m"
343 | },
344 | {
345 | "date": "10/31/2019",
346 | "value": 2500
347 | },
348 | {
349 | "date": "11/2/2019",
350 | "value": 2500
351 | },
352 | {
353 | "date": "11/7/2019",
354 | "value": 2600
355 | },
356 | {
357 | "date": "11/9/2019",
358 | "value": 2500
359 | },
360 | {
361 | "date": "11/11/2019",
362 | "value": 2300
363 | },
364 | {
365 | "date": "11/14/2019",
366 | "value": 2100
367 | },
368 | {
369 | "date": "11/18/2019",
370 | "value": 2100
371 | },
372 | {
373 | "date": "11/21/2019",
374 | "value": 2400
375 | },
376 | {
377 | "date": "11/23/2019",
378 | "value": 2700
379 | },
380 | {
381 | "date": "11/25/2019",
382 | "value": 2400
383 | },
384 | {
385 | "date": "11/26/2019",
386 | "value": 2000
387 | },
388 | {
389 | "date": "11/27/2019",
390 | "value": 2000
391 | },
392 | {
393 | "date": "11/29/2019",
394 | "value": 2500
395 | },
396 | {
397 | "date": "11/30/2019",
398 | "value": 2000
399 | },
400 | {
401 | "date": "12/8/2019",
402 | "value": 2400
403 | },
404 | {
405 | "date": "12/10/2019",
406 | "value": 2300
407 | },
408 | {
409 | "date": "12/12/2019",
410 | "value": 2000
411 | },
412 | {
413 | "date": "12/13/2019",
414 | "value": 2500
415 | },
416 | {
417 | "date": "12/15/2019",
418 | "value": 3000,
419 | "alt_unit": "m"
420 | },
421 | {
422 | "date": "12/16/2019",
423 | "value": 2100
424 | },
425 | {
426 | "date": "12/19/2019",
427 | "value": 2400
428 | },
429 | {
430 | "date": "12/21/2019",
431 | "value": 2100
432 | },
433 | {
434 | "date": "12/24/2019",
435 | "value": 2200
436 | },
437 | {
438 | "date": "12/27/2019",
439 | "value": 1800
440 | },
441 | {
442 | "date": "12/30/2019",
443 | "value": 2100
444 | },
445 | {
446 | "date": "12/31/2019",
447 | "value": 3600
448 | }
449 | ]
--------------------------------------------------------------------------------
/src/data/tanyofish-swimming-2016.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "date": "1/1/2016",
4 | "value": 2200
5 | },
6 | {
7 | "date": "1/4/2016",
8 | "value": 2200
9 | },
10 | {
11 | "date": "1/7/2016",
12 | "value": 1700
13 | },
14 | {
15 | "date": "1/9/2016",
16 | "value": 2700
17 | },
18 | {
19 | "date": "1/11/2016",
20 | "value": 2675
21 | },
22 | {
23 | "date": "1/15/2016",
24 | "value": 2500
25 | },
26 | {
27 | "date": "1/16/2016",
28 | "value": 2500
29 | },
30 | {
31 | "date": "1/23/2016",
32 | "value": 2500
33 | },
34 | {
35 | "date": "1/25/2016",
36 | "value": 2100
37 | },
38 | {
39 | "date": "1/27/2016",
40 | "value": 1800
41 | },
42 | {
43 | "date": "1/30/2016",
44 | "value": 2300
45 | },
46 | {
47 | "date": "2/2/2016",
48 | "value": 2000
49 | },
50 | {
51 | "date": "2/6/2016",
52 | "value": 2400
53 | },
54 | {
55 | "date": "2/8/2016",
56 | "value": 2200
57 | },
58 | {
59 | "date": "2/9/2016",
60 | "value": 2300
61 | },
62 | {
63 | "date": "2/12/2016",
64 | "value": 2100
65 | },
66 | {
67 | "date": "2/15/2016",
68 | "value": 2150
69 | },
70 | {
71 | "date": "2/16/2016",
72 | "value": 2600
73 | },
74 | {
75 | "date": "2/20/2016",
76 | "value": 3050
77 | },
78 | {
79 | "date": "2/24/2016",
80 | "value": 1800
81 | },
82 | {
83 | "date": "2/27/2016",
84 | "value": 2400
85 | },
86 | {
87 | "date": "3/26/2016",
88 | "value": 2300
89 | },
90 | {
91 | "date": "4/5/2016",
92 | "value": 2000
93 | },
94 | {
95 | "date": "4/6/2016",
96 | "value": 2700
97 | },
98 | {
99 | "date": "4/9/2016",
100 | "value": 2000
101 | },
102 | {
103 | "date": "4/16/2016",
104 | "value": 2350
105 | },
106 | {
107 | "date": "4/18/2016",
108 | "value": 2100
109 | },
110 | {
111 | "date": "4/20/2016",
112 | "value": 2200
113 | },
114 | {
115 | "date": "4/23/2016",
116 | "value": 2100
117 | },
118 | {
119 | "date": "4/26/2016",
120 | "value": 2000
121 | },
122 | {
123 | "date": "5/6/2016",
124 | "value": 2700
125 | },
126 | {
127 | "date": "5/7/2016",
128 | "value": 2300
129 | },
130 | {
131 | "date": "5/11/2016",
132 | "value": 1500
133 | },
134 | {
135 | "date": "5/14/2016",
136 | "value": 2500
137 | },
138 | {
139 | "date": "5/18/2016",
140 | "value": 2700
141 | },
142 | {
143 | "date": "5/20/2016",
144 | "value": 2400
145 | },
146 | {
147 | "date": "5/21/2016",
148 | "value": 2200
149 | },
150 | {
151 | "date": "5/24/2016",
152 | "value": 2100
153 | },
154 | {
155 | "date": "5/27/2016",
156 | "value": 2100
157 | },
158 | {
159 | "date": "5/28/2016",
160 | "value": 2600
161 | },
162 | {
163 | "date": "5/30/2016",
164 | "value": 3200
165 | },
166 | {
167 | "date": "6/1/2016",
168 | "value": 2500
169 | },
170 | {
171 | "date": "6/3/2016",
172 | "value": 2500
173 | },
174 | {
175 | "date": "6/6/2016",
176 | "value": 2000
177 | },
178 | {
179 | "date": "6/7/2016",
180 | "value": 2300
181 | },
182 | {
183 | "date": "6/20/2016",
184 | "value": 2450
185 | },
186 | {
187 | "date": "6/22/2016",
188 | "value": 2700
189 | },
190 | {
191 | "date": "6/23/2016",
192 | "value": 2250
193 | },
194 | {
195 | "date": "6/25/2016",
196 | "value": 3300
197 | },
198 | {
199 | "date": "6/28/2016",
200 | "value": 2200
201 | },
202 | {
203 | "date": "6/30/2016",
204 | "value": 2300
205 | },
206 | {
207 | "date": "7/1/2016",
208 | "value": 2300
209 | },
210 | {
211 | "date": "7/6/2016",
212 | "value": 2900
213 | },
214 | {
215 | "date": "7/7/2016",
216 | "value": 2500
217 | },
218 | {
219 | "date": "7/9/2016",
220 | "value": 3500
221 | },
222 | {
223 | "date": "7/11/2016",
224 | "value": 2500
225 | },
226 | {
227 | "date": "7/14/2016",
228 | "value": 2600
229 | },
230 | {
231 | "date": "7/15/2016",
232 | "value": 2400
233 | },
234 | {
235 | "date": "7/16/2016",
236 | "value": 2700
237 | },
238 | {
239 | "date": "7/21/2016",
240 | "value": 1500
241 | },
242 | {
243 | "date": "7/22/2016",
244 | "value": 2300
245 | },
246 | {
247 | "date": "7/23/2016",
248 | "value": 2500
249 | },
250 | {
251 | "date": "7/25/2016",
252 | "value": 1900
253 | },
254 | {
255 | "date": "7/26/2016",
256 | "value": 2200
257 | },
258 | {
259 | "date": "8/3/2016",
260 | "value": 3000
261 | },
262 | {
263 | "date": "8/4/2016",
264 | "value": 2400
265 | },
266 | {
267 | "date": "8/6/2016",
268 | "value": 2100
269 | },
270 | {
271 | "date": "8/9/2016",
272 | "value": 2500
273 | },
274 | {
275 | "date": "8/12/2016",
276 | "value": 900
277 | },
278 | {
279 | "date": "8/13/2016",
280 | "value": 2500
281 | },
282 | {
283 | "date": "8/17/2016",
284 | "value": 2000
285 | },
286 | {
287 | "date": "8/20/2016",
288 | "value": 2100
289 | },
290 | {
291 | "date": "8/23/2016",
292 | "value": 2500
293 | },
294 | {
295 | "date": "8/24/2016",
296 | "value": 2100
297 | },
298 | {
299 | "date": "8/27/2016",
300 | "value": 2300
301 | },
302 | {
303 | "date": "8/29/2016",
304 | "value": 1500
305 | },
306 | {
307 | "date": "9/1/2016",
308 | "value": 2100
309 | },
310 | {
311 | "date": "9/2/2016",
312 | "value": 2200
313 | },
314 | {
315 | "date": "9/5/2016",
316 | "value": 2300
317 | },
318 | {
319 | "date": "9/7/2016",
320 | "value": 1600
321 | },
322 | {
323 | "date": "9/9/2016",
324 | "value": 1900
325 | },
326 | {
327 | "date": "9/10/2016",
328 | "value": 2100
329 | },
330 | {
331 | "date": "9/13/2016",
332 | "value": 1900
333 | },
334 | {
335 | "date": "9/15/2016",
336 | "value": 1600
337 | },
338 | {
339 | "date": "9/17/2016",
340 | "value": 2600
341 | },
342 | {
343 | "date": "9/20/2016",
344 | "value": 2100
345 | },
346 | {
347 | "date": "9/23/2016",
348 | "value": 1600
349 | },
350 | {
351 | "date": "9/24/2016",
352 | "value": 1900
353 | },
354 | {
355 | "date": "9/27/2016",
356 | "value": 2020
357 | },
358 | {
359 | "date": "10/5/2016",
360 | "value": 2200
361 | },
362 | {
363 | "date": "10/20/2016",
364 | "value": 2300
365 | },
366 | {
367 | "date": "10/22/2016",
368 | "value": 2600
369 | },
370 | {
371 | "date": "10/26/2016",
372 | "value": 1900
373 | },
374 | {
375 | "date": "10/28/2016",
376 | "value": 1000
377 | },
378 | {
379 | "date": "10/29/2016",
380 | "value": 2800
381 | },
382 | {
383 | "date": "10/31/2016",
384 | "value": 1700
385 | },
386 | {
387 | "date": "11/2/2016",
388 | "value": 2300
389 | },
390 | {
391 | "date": "11/3/2016",
392 | "value": 2300
393 | },
394 | {
395 | "date": "11/4/2016",
396 | "value": 2500
397 | },
398 | {
399 | "date": "11/7/2016",
400 | "value": 2100
401 | },
402 | {
403 | "date": "11/8/2016",
404 | "value": 2700
405 | },
406 | {
407 | "date": "11/10/2016",
408 | "value": 2700
409 | },
410 | {
411 | "date": "11/11/2016",
412 | "value": 2700
413 | },
414 | {
415 | "date": "11/12/2016",
416 | "value": 3000
417 | },
418 | {
419 | "date": "11/17/2016",
420 | "value": 1800
421 | },
422 | {
423 | "date": "11/19/2016",
424 | "value": 2700
425 | },
426 | {
427 | "date": "11/22/2016",
428 | "value": 2600
429 | },
430 | {
431 | "date": "11/23/2016",
432 | "value": 3000
433 | },
434 | {
435 | "date": "11/25/2016",
436 | "value": 2800
437 | },
438 | {
439 | "date": "11/26/2016",
440 | "value": 2300
441 | },
442 | {
443 | "date": "11/29/2016",
444 | "value": 2400
445 | },
446 | {
447 | "date": "12/1/2016",
448 | "value": 2400
449 | },
450 | {
451 | "date": "12/3/2016",
452 | "value": 2400
453 | },
454 | {
455 | "date": "12/6/2016",
456 | "value": 2150
457 | },
458 | {
459 | "date": "12/8/2016",
460 | "value": 2050
461 | },
462 | {
463 | "date": "12/10/2016",
464 | "value": 2000
465 | },
466 | {
467 | "date": "12/12/2016",
468 | "value": 1500
469 | },
470 | {
471 | "date": "12/13/2016",
472 | "value": 1900
473 | },
474 | {
475 | "date": "12/26/2016",
476 | "value": 2700
477 | },
478 | {
479 | "date": "12/31/2016",
480 | "value": 2600
481 | }
482 | ]
--------------------------------------------------------------------------------
/src/data/tanyofish-swimming-2021.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "date":"1/2/2021",
4 | "value":2100
5 | },
6 | {
7 | "date":"1/3/2021",
8 | "value":2200
9 | },
10 | {
11 | "date":"1/4/2021",
12 | "value":2500
13 | },
14 | {
15 | "date":"1/6/2021",
16 | "value":2025
17 | },
18 | {
19 | "date":"1/8/2021",
20 | "value":2548
21 | },
22 | {
23 | "date":"1/10/2021",
24 | "value":2300
25 | },
26 | {
27 | "date":"1/11/2021",
28 | "value":2175
29 | },
30 | {
31 | "date":"1/13/2021",
32 | "value":1925
33 | },
34 | {
35 | "date":"1/15/2021",
36 | "value":2375
37 | },
38 | {
39 | "date":"1/16/2021",
40 | "value":2100
41 | },
42 | {
43 | "date":"1/20/2021",
44 | "value":2300
45 | },
46 | {
47 | "date":"1/21/2021",
48 | "value":2325
49 | },
50 | {
51 | "date":"1/22/2021",
52 | "value":2550
53 | },
54 | {
55 | "date":"1/23/2021",
56 | "value":2100
57 | },
58 | {
59 | "date":"1/25/2021",
60 | "value":2225
61 | },
62 | {
63 | "date":"1/26/2021",
64 | "value":2200
65 | },
66 | {
67 | "date":"1/29/2021",
68 | "value":2350
69 | },
70 | {
71 | "date":"1/30/2021",
72 | "value":1950
73 | },
74 | {
75 | "date":"1/31/2021",
76 | "value":200
77 | },
78 | {
79 | "date":"2/2/2021",
80 | "value":2300
81 | },
82 | {
83 | "date":"2/4/2021",
84 | "value":2075
85 | },
86 | {
87 | "date":"2/6/2021",
88 | "value":2050
89 | },
90 | {
91 | "date":"2/7/2021",
92 | "value":2025
93 | },
94 | {
95 | "date":"2/9/2021",
96 | "value":2225
97 | },
98 | {
99 | "date":"2/10/2021",
100 | "value":2425
101 | },
102 | {
103 | "date":"2/14/2021",
104 | "value":2700
105 | },
106 | {
107 | "date":"2/15/2021",
108 | "value":2450
109 | },
110 | {
111 | "date":"2/16/2021",
112 | "value":1900
113 | },
114 | {
115 | "date":"2/17/2021",
116 | "value":2300
117 | },
118 | {
119 | "date":"2/18/2021",
120 | "value":2775
121 | },
122 | {
123 | "date":"2/19/2021",
124 | "value":2400
125 | },
126 | {
127 | "date":"2/22/2021",
128 | "value":2200
129 | },
130 | {
131 | "date":"2/23/2021",
132 | "value":2000
133 | },
134 | {
135 | "date":"2/24/2021",
136 | "value":2525
137 | },
138 | {
139 | "date":"2/25/2021",
140 | "value":2325
141 | },
142 | {
143 | "date":"2/26/2021",
144 | "value":2600
145 | },
146 | {
147 | "date":"3/1/2021",
148 | "value":2225
149 | },
150 | {
151 | "date":"3/3/2021",
152 | "value":2350
153 | },
154 | {
155 | "date":"3/4/2021",
156 | "value":2400
157 | },
158 | {
159 | "date":"3/8/2021",
160 | "value":2450
161 | },
162 | {
163 | "date":"3/10/2021",
164 | "value":2125
165 | },
166 | {
167 | "date":"3/15/2021",
168 | "value":2050
169 | },
170 | {
171 | "date":"3/17/2021",
172 | "value":2325
173 | },
174 | {
175 | "date":"3/19/2021",
176 | "value":2550
177 | },
178 | {
179 | "date":"3/21/2021",
180 | "value":2325
181 | },
182 | {
183 | "date":"3/22/2021",
184 | "value":2300
185 | },
186 | {
187 | "date":"3/25/2021",
188 | "value":1825
189 | },
190 | {
191 | "date":"3/26/2021",
192 | "value":2300
193 | },
194 | {
195 | "date":"3/29/2021",
196 | "value":2175
197 | },
198 | {
199 | "date":"3/31/2021",
200 | "value":2325
201 | },
202 | {
203 | "date":"4/1/2021",
204 | "value":2075
205 | },
206 | {
207 | "date":"4/5/2021",
208 | "value":2325
209 | },
210 | {
211 | "date":"4/8/2021",
212 | "value":2300
213 | },
214 | {
215 | "date":"4/9/2021",
216 | "value":2175
217 | },
218 | {
219 | "date":"4/16/2021",
220 | "value":2025
221 | },
222 | {
223 | "date":"4/17/2021",
224 | "value":1169.66
225 | },
226 | {
227 | "date":"4/19/2021",
228 | "value":2500
229 | },
230 | {
231 | "date":"4/21/2021",
232 | "value":2375
233 | },
234 | {
235 | "date":"4/22/2021",
236 | "value":1950
237 | },
238 | {
239 | "date":"5/2/2021",
240 | "value":2400
241 | },
242 | {
243 | "date":"5/3/2021",
244 | "value":1700
245 | },
246 | {
247 | "date":"5/5/2021",
248 | "value":2225
249 | },
250 | {
251 | "date":"5/7/2021",
252 | "value":2000
253 | },
254 | {
255 | "date":"5/10/2021",
256 | "value":2100
257 | },
258 | {
259 | "date":"5/12/2021",
260 | "value":2000
261 | },
262 | {
263 | "date":"5/17/2021",
264 | "value":2000
265 | },
266 | {
267 | "date":"5/19/2021",
268 | "value":2300
269 | },
270 | {
271 | "date":"5/21/2021",
272 | "value":1925
273 | },
274 | {
275 | "date":"5/24/2021",
276 | "value":2300
277 | },
278 | {
279 | "date":"5/25/2021",
280 | "value":2125
281 | },
282 | {
283 | "date":"5/27/2021",
284 | "value":1325
285 | },
286 | {
287 | "date":"6/2/2021",
288 | "value":2250
289 | },
290 | {
291 | "date":"6/3/2021",
292 | "value":2025
293 | },
294 | {
295 | "date":"6/4/2021",
296 | "value":2025
297 | },
298 | {
299 | "date":"6/9/2021",
300 | "value":2325
301 | },
302 | {
303 | "date":"6/10/2021",
304 | "value":2025
305 | },
306 | {
307 | "date":"6/11/2021",
308 | "value":2200
309 | },
310 | {
311 | "date":"6/27/2021",
312 | "value":809.46
313 | },
314 | {
315 | "date":"6/28/2021",
316 | "value":2145
317 | },
318 | {
319 | "date":"7/7/2021",
320 | "value":1800
321 | },
322 | {
323 | "date":"7/11/2021",
324 | "value":2100
325 | },
326 | {
327 | "date":"7/12/2021",
328 | "value":1250
329 | },
330 | {
331 | "date":"7/13/2021",
332 | "value":1700
333 | },
334 | {
335 | "date":"7/15/2021",
336 | "value":1550
337 | },
338 | {
339 | "date":"7/18/2021",
340 | "value":2275
341 | },
342 | {
343 | "date":"7/20/2021",
344 | "value":2425
345 | },
346 | {
347 | "date":"7/23/2021",
348 | "value":1625
349 | },
350 | {
351 | "date":"7/24/2021",
352 | "value":1875
353 | },
354 | {
355 | "date":"7/27/2021",
356 | "value":2550
357 | },
358 | {
359 | "date":"7/29/2021",
360 | "value":2150
361 | },
362 | {
363 | "date":"7/31/2021",
364 | "value":1375
365 | },
366 | {
367 | "date":"8/2/2021",
368 | "value":1625
369 | },
370 | {
371 | "date":"8/4/2021",
372 | "value":1900
373 | },
374 | {
375 | "date":"8/6/2021",
376 | "value":1550
377 | },
378 | {
379 | "date":"8/9/2021",
380 | "value":1925
381 | },
382 | {
383 | "date":"8/11/2021",
384 | "value":1700
385 | },
386 | {
387 | "date":"8/13/2021",
388 | "value":1675
389 | },
390 | {
391 | "date":"8/18/2021",
392 | "value":2225
393 | },
394 | {
395 | "date":"8/21/2021",
396 | "value":1775
397 | },
398 | {
399 | "date":"8/26/2021",
400 | "value":2750
401 | },
402 | {
403 | "date":"8/30/2021",
404 | "value":2100
405 | },
406 | {
407 | "date":"9/1/2021",
408 | "value":2450
409 | },
410 | {
411 | "date":"9/3/2021",
412 | "value":2100
413 | },
414 | {
415 | "date":"9/4/2021",
416 | "value":2075
417 | },
418 | {
419 | "date":"9/7/2021",
420 | "value":2200
421 | },
422 | {
423 | "date":"9/9/2021",
424 | "value":2200
425 | },
426 | {
427 | "date":"9/11/2021",
428 | "value":2400
429 | },
430 | {
431 | "date":"9/13/2021",
432 | "value":1900
433 | },
434 | {
435 | "date":"9/15/2021",
436 | "value":1350
437 | },
438 | {
439 | "date":"9/17/2021",
440 | "value":1975
441 | },
442 | {
443 | "date":"9/18/2021",
444 | "value":1775
445 | },
446 | {
447 | "date":"10/18/2021",
448 | "value":1374.91
449 | },
450 | {
451 | "date":"10/19/2021",
452 | "value":3124.8599999999997
453 | },
454 | {
455 | "date":"10/20/2021",
456 | "value":4746.83
457 | },
458 | {
459 | "date":"10/21/2021",
460 | "value":1612.16
461 | },
462 | {
463 | "date":"10/22/2021",
464 | "value":4486.99
465 | },
466 | {
467 | "date":"10/29/2021",
468 | "value":3399
469 | },
470 | {
471 | "date":"11/1/2021",
472 | "value":2574
473 | },
474 | {
475 | "date":"11/2/2021",
476 | "value":2508
477 | },
478 | {
479 | "date":"11/3/2021",
480 | "value":1914
481 | },
482 | {
483 | "date":"11/4/2021",
484 | "value":3564
485 | },
486 | {
487 | "date":"11/6/2021",
488 | "value":2937
489 | },
490 | {
491 | "date":"11/7/2021",
492 | "value":3597
493 | },
494 | {
495 | "date":"11/8/2021",
496 | "value":2277
497 | },
498 | {
499 | "date":"11/9/2021",
500 | "value":1848
501 | },
502 | {
503 | "date":"11/11/2021",
504 | "value":2970
505 | },
506 | {
507 | "date":"11/15/2021",
508 | "value":2508
509 | },
510 | {
511 | "date":"11/17/2021",
512 | "value":2079
513 | },
514 | {
515 | "date":"11/18/2021",
516 | "value":3135
517 | },
518 | {
519 | "date":"11/20/2021",
520 | "value":3036
521 | },
522 | {
523 | "date":"11/21/2021",
524 | "value":3465
525 | },
526 | {
527 | "date":"11/22/2021",
528 | "value":2310
529 | },
530 | {
531 | "date":"11/26/2021",
532 | "value":2376
533 | },
534 | {
535 | "date":"11/27/2021",
536 | "value":2640
537 | },
538 | {
539 | "date":"11/29/2021",
540 | "value":2800
541 | },
542 | {
543 | "date":"12/5/2021",
544 | "value":3300
545 | },
546 | {
547 | "date":"12/6/2021",
548 | "value":2433.33
549 | },
550 | {
551 | "date":"12/7/2021",
552 | "value":2000
553 | },
554 | {
555 | "date":"12/9/2021",
556 | "value":2900
557 | },
558 | {
559 | "date":"12/10/2021",
560 | "value":3433.33
561 | },
562 | {
563 | "date":"12/12/2021",
564 | "value":3433.33
565 | },
566 | {
567 | "date":"12/21/2021",
568 | "value":2166.67
569 | },
570 | {
571 | "date":"12/24/2021",
572 | "value":1900
573 | },
574 | {
575 | "date":"12/26/2021",
576 | "value":3333.33
577 | },
578 | {
579 | "date":"12/27/2021",
580 | "value":2533.33
581 | },
582 | {
583 | "date":"12/29/2021",
584 | "value":2333.33
585 | }
586 | ]
--------------------------------------------------------------------------------
/src/data/plabinu-swimming-2016.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "date": "2/1/2016",
4 | "value": 1900
5 | },
6 | {
7 | "date": "2/5/2016",
8 | "value": 1350
9 | },
10 | {
11 | "date": "2/12/2016",
12 | "value": 1300
13 | },
14 | {
15 | "date": "2/13/2016",
16 | "value": 1600
17 | },
18 | {
19 | "date": "2/15/2016",
20 | "value": 1900
21 | },
22 | {
23 | "date": "2/16/2016",
24 | "value": 700
25 | },
26 | {
27 | "date": "2/17/2016",
28 | "value": 750
29 | },
30 | {
31 | "date": "2/18/2016",
32 | "value": 800
33 | },
34 | {
35 | "date": "2/19/2016",
36 | "value": 1400
37 | },
38 | {
39 | "date": "2/22/2016",
40 | "value": 1650
41 | },
42 | {
43 | "date": "2/23/2016",
44 | "value": 650
45 | },
46 | {
47 | "date": "2/24/2016",
48 | "value": 1000
49 | },
50 | {
51 | "date": "2/25/2016",
52 | "value": 850
53 | },
54 | {
55 | "date": "2/26/2016",
56 | "value": 1200
57 | },
58 | {
59 | "date": "2/29/2016",
60 | "value": 1950
61 | },
62 | {
63 | "date": "3/2/2016",
64 | "value": 750
65 | },
66 | {
67 | "date": "3/4/2016",
68 | "value": 1450
69 | },
70 | {
71 | "date": "3/7/2016",
72 | "value": 1950
73 | },
74 | {
75 | "date": "3/8/2016",
76 | "value": 550
77 | },
78 | {
79 | "date": "3/9/2016",
80 | "value": 1500
81 | },
82 | {
83 | "date": "3/14/2016",
84 | "value": 1750
85 | },
86 | {
87 | "date": "3/16/2016",
88 | "value": 350
89 | },
90 | {
91 | "date": "3/17/2016",
92 | "value": 1600
93 | },
94 | {
95 | "date": "3/18/2016",
96 | "value": 1700
97 | },
98 | {
99 | "date": "3/19/2016",
100 | "value": 1300
101 | },
102 | {
103 | "date": "3/21/2016",
104 | "value": 2050
105 | },
106 | {
107 | "date": "3/23/2016",
108 | "value": 1300
109 | },
110 | {
111 | "date": "3/25/2016",
112 | "value": 1625
113 | },
114 | {
115 | "date": "3/26/2016",
116 | "value": 1450
117 | },
118 | {
119 | "date": "3/29/2016",
120 | "value": 2000
121 | },
122 | {
123 | "date": "3/30/2016",
124 | "value": 1350
125 | },
126 | {
127 | "date": "4/4/2016",
128 | "value": 1900
129 | },
130 | {
131 | "date": "4/8/2016",
132 | "value": 1600
133 | },
134 | {
135 | "date": "4/11/2016",
136 | "value": 2200
137 | },
138 | {
139 | "date": "4/15/2016",
140 | "value": 1200
141 | },
142 | {
143 | "date": "4/18/2016",
144 | "value": 1500
145 | },
146 | {
147 | "date": "4/20/2016",
148 | "value": 800
149 | },
150 | {
151 | "date": "4/26/2016",
152 | "value": 1800
153 | },
154 | {
155 | "date": "4/29/2016",
156 | "value": 1200
157 | },
158 | {
159 | "date": "5/2/2016",
160 | "value": 1740
161 | },
162 | {
163 | "date": "5/9/2016",
164 | "value": 2000
165 | },
166 | {
167 | "date": "5/11/2016",
168 | "value": 1000
169 | },
170 | {
171 | "date": "5/13/2016",
172 | "value": 1700
173 | },
174 | {
175 | "date": "5/16/2016",
176 | "value": 2000
177 | },
178 | {
179 | "date": "5/18/2016",
180 | "value": 1350
181 | },
182 | {
183 | "date": "5/27/2016",
184 | "value": 1550
185 | },
186 | {
187 | "date": "6/1/2016",
188 | "value": 1200
189 | },
190 | {
191 | "date": "6/15/2016",
192 | "value": 1150
193 | },
194 | {
195 | "date": "6/17/2016",
196 | "value": 1200
197 | },
198 | {
199 | "date": "6/18/2016",
200 | "value": 1900
201 | },
202 | {
203 | "date": "6/20/2016",
204 | "value": 1800
205 | },
206 | {
207 | "date": "6/22/2016",
208 | "value": 1600
209 | },
210 | {
211 | "date": "6/24/2016",
212 | "value": 1000
213 | },
214 | {
215 | "date": "6/25/2016",
216 | "value": 1750
217 | },
218 | {
219 | "date": "6/27/2016",
220 | "value": 1450
221 | },
222 | {
223 | "date": "6/29/2016",
224 | "value": 1000
225 | },
226 | {
227 | "date": "7/1/2016",
228 | "value": 1500
229 | },
230 | {
231 | "date": "7/4/2016",
232 | "value": 1750
233 | },
234 | {
235 | "date": "7/6/2016",
236 | "value": 1250
237 | },
238 | {
239 | "date": "7/8/2016",
240 | "value": 1650
241 | },
242 | {
243 | "date": "7/11/2016",
244 | "value": 1800
245 | },
246 | {
247 | "date": "7/13/2016",
248 | "value": 1200
249 | },
250 | {
251 | "date": "7/15/2016",
252 | "value": 1650
253 | },
254 | {
255 | "date": "7/18/2016",
256 | "value": 1850
257 | },
258 | {
259 | "date": "7/20/2016",
260 | "value": 1300
261 | },
262 | {
263 | "date": "7/22/2016",
264 | "value": 1550
265 | },
266 | {
267 | "date": "7/25/2016",
268 | "value": 1900
269 | },
270 | {
271 | "date": "7/27/2016",
272 | "value": 1350
273 | },
274 | {
275 | "date": "7/29/2016",
276 | "value": 1300
277 | },
278 | {
279 | "date": "8/3/2016",
280 | "value": 1350
281 | },
282 | {
283 | "date": "8/8/2016",
284 | "value": 2000
285 | },
286 | {
287 | "date": "8/10/2016",
288 | "value": 1350
289 | },
290 | {
291 | "date": "8/12/2016",
292 | "value": 1550
293 | },
294 | {
295 | "date": "8/17/2016",
296 | "value": 1350
297 | },
298 | {
299 | "date": "8/22/2016",
300 | "value": 1950
301 | },
302 | {
303 | "date": "8/24/2016",
304 | "value": 1400
305 | },
306 | {
307 | "date": "8/26/2016",
308 | "value": 1500
309 | },
310 | {
311 | "date": "8/29/2016",
312 | "value": 1850
313 | },
314 | {
315 | "date": "8/31/2016",
316 | "value": 1700
317 | },
318 | {
319 | "date": "9/2/2016",
320 | "value": 1350
321 | },
322 | {
323 | "date": "9/5/2016",
324 | "value": 1900
325 | },
326 | {
327 | "date": "9/7/2016",
328 | "value": 1350
329 | },
330 | {
331 | "date": "9/10/2016",
332 | "value": 1350
333 | },
334 | {
335 | "date": "9/12/2016",
336 | "value": 1950
337 | },
338 | {
339 | "date": "9/21/2016",
340 | "value": 1450
341 | },
342 | {
343 | "date": "9/24/2016",
344 | "value": 1550
345 | },
346 | {
347 | "date": "9/26/2016",
348 | "value": 1900
349 | },
350 | {
351 | "date": "9/28/2016",
352 | "value": 1550
353 | },
354 | {
355 | "date": "9/30/2016",
356 | "value": 1300
357 | },
358 | {
359 | "date": "10/5/2016",
360 | "value": 1550
361 | },
362 | {
363 | "date": "10/7/2016",
364 | "value": 1600
365 | },
366 | {
367 | "date": "10/10/2016",
368 | "value": 1850
369 | },
370 | {
371 | "date": "10/14/2016",
372 | "value": 1450
373 | },
374 | {
375 | "date": "10/17/2016",
376 | "value": 1850
377 | },
378 | {
379 | "date": "10/19/2016",
380 | "value": 1450
381 | },
382 | {
383 | "date": "10/21/2016",
384 | "value": 1600
385 | },
386 | {
387 | "date": "10/24/2016",
388 | "value": 1800
389 | },
390 | {
391 | "date": "10/27/2016",
392 | "value": 1650
393 | },
394 | {
395 | "date": "10/28/2016",
396 | "value": 1650
397 | },
398 | {
399 | "date": "10/31/2016",
400 | "value": 1650
401 | },
402 | {
403 | "date": "11/2/2016",
404 | "value": 1600
405 | },
406 | {
407 | "date": "11/7/2016",
408 | "value": 1800
409 | },
410 | {
411 | "date": "11/9/2016",
412 | "value": 1500
413 | },
414 | {
415 | "date": "11/11/2016",
416 | "value": 1500
417 | },
418 | {
419 | "date": "11/14/2016",
420 | "value": 1800
421 | },
422 | {
423 | "date": "11/16/2016",
424 | "value": 1150
425 | },
426 | {
427 | "date": "11/18/2016",
428 | "value": 1350
429 | },
430 | {
431 | "date": "11/21/2016",
432 | "value": 1650
433 | },
434 | {
435 | "date": "11/23/2016",
436 | "value": 1250
437 | },
438 | {
439 | "date": "11/25/2016",
440 | "value": 1350
441 | },
442 | {
443 | "date": "11/28/2016",
444 | "value": 1600
445 | },
446 | {
447 | "date": "11/30/2016",
448 | "value": 1400
449 | },
450 | {
451 | "date": "12/1/2016",
452 | "value": 1550
453 | },
454 | {
455 | "date": "12/7/2016",
456 | "value": 1400
457 | },
458 | {
459 | "date": "12/9/2016",
460 | "value": 1200
461 | },
462 | {
463 | "date": "12/12/2016",
464 | "value": 1800
465 | },
466 | {
467 | "date": "12/14/2016",
468 | "value": 1300
469 | },
470 | {
471 | "date": "12/16/2016",
472 | "value": 1500
473 | },
474 | {
475 | "date": "12/19/2016",
476 | "value": 1800
477 | },
478 | {
479 | "date": "12/21/2016",
480 | "value": 1300
481 | },
482 | {
483 | "date": "12/23/2016",
484 | "value": 1450
485 | },
486 | {
487 | "date": "12/26/2016",
488 | "value": 2000
489 | },
490 | {
491 | "date": "12/28/2016",
492 | "value": 1650
493 | },
494 | {
495 | "date": "12/30/2016",
496 | "value": 1700
497 | }
498 | ]
--------------------------------------------------------------------------------
/src/data/tanyofish-swimming-2023.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "date":"1/1/2023",
4 | "value":3233.33
5 | },
6 | {
7 | "date":"1/7/2023",
8 | "value":3566.67
9 | },
10 | {
11 | "date":"1/8/2023",
12 | "value":3033.33
13 | },
14 | {
15 | "date":"1/9/2023",
16 | "value":2533.33
17 | },
18 | {
19 | "date":"1/12/2023",
20 | "value":3100
21 | },
22 | {
23 | "date":"1/15/2023",
24 | "value":3400
25 | },
26 | {
27 | "date":"1/16/2023",
28 | "value":2866.67
29 | },
30 | {
31 | "date":"1/21/2023",
32 | "value":2600
33 | },
34 | {
35 | "date":"1/23/2023",
36 | "value":1933.33
37 | },
38 | {
39 | "date":"1/27/2023",
40 | "value":3800
41 | },
42 | {
43 | "date":"1/29/2023",
44 | "value":2466.67
45 | },
46 | {
47 | "date":"2/5/2023",
48 | "value":3233.33
49 | },
50 | {
51 | "date":"2/9/2023",
52 | "value":3033.33
53 | },
54 | {
55 | "date":"2/12/2023",
56 | "value":3266.67
57 | },
58 | {
59 | "date":"2/16/2023",
60 | "value":2866.67
61 | },
62 | {
63 | "date":"2/18/2023",
64 | "value":2000
65 | },
66 | {
67 | "date":"2/19/2023",
68 | "value":3000
69 | },
70 | {
71 | "date":"2/20/2023",
72 | "value":2733.33
73 | },
74 | {
75 | "date":"2/25/2023",
76 | "value":3000
77 | },
78 | {
79 | "date":"3/1/2023",
80 | "value":2333.33
81 | },
82 | {
83 | "date":"3/2/2023",
84 | "value":3100
85 | },
86 | {
87 | "date":"3/11/2023",
88 | "value":3333.33
89 | },
90 | {
91 | "date":"3/13/2023",
92 | "value":2566.67
93 | },
94 | {
95 | "date":"3/14/2023",
96 | "value":2533.33
97 | },
98 | {
99 | "date":"3/16/2023",
100 | "value":2800
101 | },
102 | {
103 | "date":"3/18/2023",
104 | "value":300
105 | },
106 | {
107 | "date":"3/24/2023",
108 | "value":3033.33
109 | },
110 | {
111 | "date":"3/26/2023",
112 | "value":3366.67
113 | },
114 | {
115 | "date":"3/29/2023",
116 | "value":2433.33
117 | },
118 | {
119 | "date":"3/30/2023",
120 | "value":2766.67
121 | },
122 | {
123 | "date":"4/2/2023",
124 | "value":2733.33
125 | },
126 | {
127 | "date":"4/8/2023",
128 | "value":3233.33
129 | },
130 | {
131 | "date":"4/9/2023",
132 | "value":3000
133 | },
134 | {
135 | "date":"4/16/2023",
136 | "value":2533.33
137 | },
138 | {
139 | "date":"4/18/2023",
140 | "value":2766.67
141 | },
142 | {
143 | "date":"4/20/2023",
144 | "value":3266.67
145 | },
146 | {
147 | "date":"4/22/2023",
148 | "value":2466.67
149 | },
150 | {
151 | "date":"4/24/2023",
152 | "value":2466.67
153 | },
154 | {
155 | "date":"4/25/2023",
156 | "value":2733.33
157 | },
158 | {
159 | "date":"4/27/2023",
160 | "value":2566.67
161 | },
162 | {
163 | "date":"4/29/2023",
164 | "value":2466.67
165 | },
166 | {
167 | "date":"5/4/2023",
168 | "value":2100
169 | },
170 | {
171 | "date":"5/6/2023",
172 | "value":2766.67
173 | },
174 | {
175 | "date":"5/7/2023",
176 | "value":2033.33
177 | },
178 | {
179 | "date":"5/9/2023",
180 | "value":1966.67
181 | },
182 | {
183 | "date":"5/14/2023",
184 | "value":2766.67
185 | },
186 | {
187 | "date":"5/16/2023",
188 | "value":1933.33
189 | },
190 | {
191 | "date":"5/19/2023",
192 | "value":2100
193 | },
194 | {
195 | "date":"5/21/2023",
196 | "value":2966.67
197 | },
198 | {
199 | "date":"5/23/2023",
200 | "value":1285
201 | },
202 | {
203 | "date":"6/3/2023",
204 | "value":1276.29
205 | },
206 | {
207 | "date":"6/4/2023",
208 | "value":5249.37
209 | },
210 | {
211 | "date":"6/5/2023",
212 | "value":4430.389999999999
213 | },
214 | {
215 | "date":"6/6/2023",
216 | "value":5628.0199999999995
217 | },
218 | {
219 | "date":"6/7/2023",
220 | "value":5995.69
221 | },
222 | {
223 | "date":"6/8/2023",
224 | "value":1003.26
225 | },
226 | {
227 | "date":"6/13/2023",
228 | "value":2734.03
229 | },
230 | {
231 | "date":"6/14/2023",
232 | "value":3062.12
233 | },
234 | {
235 | "date":"6/15/2023",
236 | "value":1968.5
237 | },
238 | {
239 | "date":"6/16/2023",
240 | "value":2351.27
241 | },
242 | {
243 | "date":"6/18/2023",
244 | "value":3379.27
245 | },
246 | {
247 | "date":"6/20/2023",
248 | "value":2077.87
249 | },
250 | {
251 | "date":"6/21/2023",
252 | "value":974.63
253 | },
254 | {
255 | "date":"6/22/2023",
256 | "value":802.28
257 | },
258 | {
259 | "date":"6/23/2023",
260 | "value":2241.91
261 | },
262 | {
263 | "date":"7/1/2023",
264 | "value":2077.52
265 | },
266 | {
267 | "date":"7/2/2023",
268 | "value":2866.67
269 | },
270 | {
271 | "date":"7/4/2023",
272 | "value":2733.33
273 | },
274 | {
275 | "date":"7/6/2023",
276 | "value":2633.33
277 | },
278 | {
279 | "date":"7/8/2023",
280 | "value":2233.33
281 | },
282 | {
283 | "date":"7/9/2023",
284 | "value":1233.33
285 | },
286 | {
287 | "date":"7/11/2023",
288 | "value":2566.67
289 | },
290 | {
291 | "date":"7/13/2023",
292 | "value":2133.33
293 | },
294 | {
295 | "date":"7/16/2023",
296 | "value":2800
297 | },
298 | {
299 | "date":"7/18/2023",
300 | "value":2566.67
301 | },
302 | {
303 | "date":"7/20/2023",
304 | "value":2900
305 | },
306 | {
307 | "date":"7/23/2023",
308 | "value":2600
309 | },
310 | {
311 | "date":"7/25/2023",
312 | "value":2633.33
313 | },
314 | {
315 | "date":"7/27/2023",
316 | "value":2233.33
317 | },
318 | {
319 | "date":"7/30/2023",
320 | "value":2833.33
321 | },
322 | {
323 | "date":"8/1/2023",
324 | "value":1866.67
325 | },
326 | {
327 | "date":"8/3/2023",
328 | "value":2800
329 | },
330 | {
331 | "date":"8/5/2023",
332 | "value":2633.33
333 | },
334 | {
335 | "date":"8/6/2023",
336 | "value":3000
337 | },
338 | {
339 | "date":"8/8/2023",
340 | "value":2733.33
341 | },
342 | {
343 | "date":"8/10/2023",
344 | "value":2633.33
345 | },
346 | {
347 | "date":"8/13/2023",
348 | "value":1466.67
349 | },
350 | {
351 | "date":"8/15/2023",
352 | "value":2566.67
353 | },
354 | {
355 | "date":"8/17/2023",
356 | "value":2600
357 | },
358 | {
359 | "date":"8/19/2023",
360 | "value":3066.67
361 | },
362 | {
363 | "date":"8/24/2023",
364 | "value":2700
365 | },
366 | {
367 | "date":"8/27/2023",
368 | "value":3166.67
369 | },
370 | {
371 | "date":"8/29/2023",
372 | "value":2766.67
373 | },
374 | {
375 | "date":"8/31/2023",
376 | "value":2833.33
377 | },
378 | {
379 | "date":"9/4/2023",
380 | "value":3566.67
381 | },
382 | {
383 | "date":"9/7/2023",
384 | "value":2400
385 | },
386 | {
387 | "date":"9/9/2023",
388 | "value":3366.67
389 | },
390 | {
391 | "date":"9/10/2023",
392 | "value":2100
393 | },
394 | {
395 | "date":"9/12/2023",
396 | "value":2533.33
397 | },
398 | {
399 | "date":"9/14/2023",
400 | "value":2900
401 | },
402 | {
403 | "date":"9/16/2023",
404 | "value":2666.67
405 | },
406 | {
407 | "date":"9/19/2023",
408 | "value":2666.67
409 | },
410 | {
411 | "date":"9/21/2023",
412 | "value":2466.67
413 | },
414 | {
415 | "date":"9/23/2023",
416 | "value":3666.67
417 | },
418 | {
419 | "date":"9/24/2023",
420 | "value":2133.33
421 | },
422 | {
423 | "date":"9/28/2023",
424 | "value":2500
425 | },
426 | {
427 | "date":"10/1/2023",
428 | "value":3166.67
429 | },
430 | {
431 | "date":"10/3/2023",
432 | "value":2466.67
433 | },
434 | {
435 | "date":"10/5/2023",
436 | "value":2766.67
437 | },
438 | {
439 | "date":"10/8/2023",
440 | "value":2733.33
441 | },
442 | {
443 | "date":"10/10/2023",
444 | "value":2033.33
445 | },
446 | {
447 | "date":"10/12/2023",
448 | "value":2633.33
449 | },
450 | {
451 | "date":"10/14/2023",
452 | "value":2366.67
453 | },
454 | {
455 | "date":"10/17/2023",
456 | "value":2666.67
457 | },
458 | {
459 | "date":"10/19/2023",
460 | "value":2500
461 | },
462 | {
463 | "date":"10/21/2023",
464 | "value":2000
465 | },
466 | {
467 | "date":"10/24/2023",
468 | "value":2766.67
469 | },
470 | {
471 | "date":"10/26/2023",
472 | "value":2166.67
473 | },
474 | {
475 | "date":"10/28/2023",
476 | "value":2600
477 | },
478 | {
479 | "date":"10/29/2023",
480 | "value":2433.33
481 | },
482 | {
483 | "date":"11/5/2023",
484 | "value":2466.67
485 | },
486 | {
487 | "date":"11/7/2023",
488 | "value":2166.67
489 | },
490 | {
491 | "date":"11/9/2023",
492 | "value":2566.67
493 | },
494 | {
495 | "date":"11/11/2023",
496 | "value":2366.67
497 | },
498 | {
499 | "date":"11/12/2023",
500 | "value":1500
501 | },
502 | {
503 | "date":"11/14/2023",
504 | "value":2633.33
505 | },
506 | {
507 | "date":"11/16/2023",
508 | "value":2866.67
509 | },
510 | {
511 | "date":"11/18/2023",
512 | "value":3266.67
513 | },
514 | {
515 | "date":"11/21/2023",
516 | "value":2333.33
517 | },
518 | {
519 | "date":"11/24/2023",
520 | "value":2833.33
521 | },
522 | {
523 | "date":"11/26/2023",
524 | "value":4066.67
525 | },
526 | {
527 | "date":"11/30/2023",
528 | "value":2600
529 | },
530 | {
531 | "date":"12/2/2023",
532 | "value":3133.33
533 | },
534 | {
535 | "date":"12/7/2023",
536 | "value":2466.67
537 | },
538 | {
539 | "date":"12/9/2023",
540 | "value":2700
541 | },
542 | {
543 | "date":"12/12/2023",
544 | "value":2733.33
545 | },
546 | {
547 | "date":"12/14/2023",
548 | "value":2333.33
549 | },
550 | {
551 | "date":"12/16/2023",
552 | "value":2966.67
553 | },
554 | {
555 | "date":"12/17/2023",
556 | "value":3200
557 | },
558 | {
559 | "date":"12/19/2023",
560 | "value":1766.67
561 | },
562 | {
563 | "date":"12/21/2023",
564 | "value":2600
565 | },
566 | {
567 | "date":"12/23/2023",
568 | "value":3333.33
569 | },
570 | {
571 | "date":"12/25/2023",
572 | "value":3566.67
573 | },
574 | {
575 | "date":"12/28/2023",
576 | "value":2966.67
577 | }
578 | ]
--------------------------------------------------------------------------------