├── 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 |
    30 |
    {d.year}
    31 |
      {elms}
    32 |
    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 |
    27 |
    28 | 29 | 30 | Total {capitalize(metric)} ({metric}s) 31 | 32 | 33 | 34 | Occurance (times) 35 | 36 |
    37 |
    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 | 30 | 41 | {unit === 'day' && } 42 | {unit !== 'month' && } 43 | 44 | 45 | {this.state.isHovered && } 56 | 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 |
    46 |
    47 |
    48 |
    49 |
    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 | 109 | 110 | d[selection])} 115 | color={color} 116 | /> 117 | 118 | 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 |
    89 |
    90 | Share 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | Fork on 99 | 100 | 101 | 102 | 103 | {setting.dataSource && 104 | Powered by 105 | {setting.dataSource.url != null ? 106 | 107 | {setting.dataSource.name} 108 | : ` ${setting.dataSource.name}`} 109 | 110 | } 111 |
    112 |
    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 | ] --------------------------------------------------------------------------------