├── .eslintignore ├── .gitignore ├── favicon.ico ├── .gitattributes ├── logos ├── aatishb.png ├── microbe.png ├── aatishb-bw.png ├── microbe-invert.png ├── minutephysics.png ├── covid-trends-logo.png ├── minutephysics-invert.png └── covid-trends-logo-nowords.png ├── all-contributors-photos ├── connie.jpg ├── arkarup.jpg └── bybee-finley.jpg ├── package.json ├── icons ├── play.svg └── pause.svg ├── .github └── workflows │ ├── lighthouse.yml │ └── nodejs.yml ├── LICENSE.txt ├── normalize.css ├── .eslintrc.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── style.css ├── .all-contributorsrc ├── index.html ├── README.md ├── vue-definitions.js └── libraries └── vue.min.js /.eslintignore: -------------------------------------------------------------------------------- 1 | libraries -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aatishb/covidtrends/HEAD/favicon.ico -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /logos/aatishb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aatishb/covidtrends/HEAD/logos/aatishb.png -------------------------------------------------------------------------------- /logos/microbe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aatishb/covidtrends/HEAD/logos/microbe.png -------------------------------------------------------------------------------- /logos/aatishb-bw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aatishb/covidtrends/HEAD/logos/aatishb-bw.png -------------------------------------------------------------------------------- /logos/microbe-invert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aatishb/covidtrends/HEAD/logos/microbe-invert.png -------------------------------------------------------------------------------- /logos/minutephysics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aatishb/covidtrends/HEAD/logos/minutephysics.png -------------------------------------------------------------------------------- /logos/covid-trends-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aatishb/covidtrends/HEAD/logos/covid-trends-logo.png -------------------------------------------------------------------------------- /logos/minutephysics-invert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aatishb/covidtrends/HEAD/logos/minutephysics-invert.png -------------------------------------------------------------------------------- /all-contributors-photos/connie.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aatishb/covidtrends/HEAD/all-contributors-photos/connie.jpg -------------------------------------------------------------------------------- /all-contributors-photos/arkarup.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aatishb/covidtrends/HEAD/all-contributors-photos/arkarup.jpg -------------------------------------------------------------------------------- /logos/covid-trends-logo-nowords.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aatishb/covidtrends/HEAD/logos/covid-trends-logo-nowords.png -------------------------------------------------------------------------------- /all-contributors-photos/bybee-finley.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aatishb/covidtrends/HEAD/all-contributors-photos/bybee-finley.jpg -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "test": "eslint . --report-unused-disable-directives" 4 | }, 5 | "devDependencies": { 6 | "eslint": "^6.8.0" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /icons/play.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/workflows/lighthouse.yml: -------------------------------------------------------------------------------- 1 | name: Lighthouse Audit 2 | on: pull_request 3 | 4 | jobs: 5 | audit: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - name: Audit Netlify deploy preview 9 | uses: jakejarvis/lighthouse-action@master 10 | with: 11 | netlify_site: 'frosty-benz-8c81bf.netlify.app' 12 | - uses: actions/upload-artifact@master 13 | with: 14 | name: report 15 | path: './report' 16 | -------------------------------------------------------------------------------- /icons/pause.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Node.js CI 5 | 6 | on: 7 | push: 8 | branches: [ master ] 9 | pull_request: 10 | branches: [ master ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | strategy: 18 | matrix: 19 | node-version: [12.x] 20 | 21 | steps: 22 | - uses: actions/checkout@v2 23 | - name: Use Node.js ${{ matrix.node-version }} 24 | uses: actions/setup-node@v1 25 | with: 26 | node-version: ${{ matrix.node-version }} 27 | - run: npm ci 28 | - run: npm run build --if-present 29 | - run: npm test 30 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2020 Aatish Bhatia 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | 9 | -------------------------------------------------------------------------------- /normalize.css: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ 2 | v2.0 | 20110126 3 | License: none (public domain) 4 | */ 5 | 6 | html, body, div, span, applet, object, iframe, 7 | h1, h2, h3, h4, h5, h6, p, blockquote, 8 | a, abbr, acronym, address, big, cite, 9 | del, dfn, em, img, ins, kbd, q, s, samp, 10 | small, strike, strong, sub, sup, tt, var, 11 | b, u, i, center, 12 | dl, dt, dd, ol, ul, li, 13 | fieldset, form, label, legend, 14 | table, caption, tbody, tfoot, thead, tr, th, td, 15 | article, aside, canvas, details, embed, 16 | figure, figcaption, footer, header, hgroup, 17 | menu, nav, output, ruby, section, summary, 18 | time, mark, audio, video { 19 | margin: 0; 20 | padding: 0; 21 | border: 0; 22 | font-size: 100%; 23 | font: inherit; 24 | vertical-align: baseline; 25 | } 26 | /* HTML5 display-role reset for older browsers */ 27 | article, aside, details, figcaption, figure, 28 | footer, header, hgroup, menu, nav, section { 29 | display: block; 30 | } 31 | body { 32 | line-height: 1; 33 | } 34 | ol, ul { 35 | list-style: none; 36 | } 37 | blockquote, q { 38 | quotes: none; 39 | } 40 | blockquote:before, blockquote:after, 41 | q:before, q:after { 42 | content: ''; 43 | content: none; 44 | } 45 | table { 46 | border-collapse: collapse; 47 | border-spacing: 0; 48 | } -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint:recommended", 3 | "env": { 4 | "browser": true, 5 | "es6": true 6 | }, 7 | "globals": { 8 | "Vue": "readonly", 9 | "Plotly": "readonly" 10 | }, 11 | "rules": { 12 | "array-bracket-spacing": ["error", "never"], 13 | "arrow-body-style": "error", 14 | "arrow-spacing": "error", 15 | "block-spacing": "error", 16 | "camelcase": "error", 17 | "comma-spacing": "error", 18 | "comma-style": "error", 19 | "computed-property-spacing": "error", 20 | "dot-location": ["error", "property"], 21 | "eol-last": "error", 22 | "func-call-spacing": "error", 23 | "indent": ["error", 2, { "SwitchCase": 1 }], 24 | "key-spacing": "error", 25 | "keyword-spacing": "error", 26 | "linebreak-style": "error", 27 | "no-alert": "error", 28 | "no-array-constructor": "error", 29 | "no-console": "error", 30 | "no-multi-spaces": ["error", {"ignoreEOLComments": true}], 31 | "no-multiple-empty-lines": "error", 32 | "no-new-func": "error", 33 | "no-new-object": "error", 34 | "no-spaced-func": "error", 35 | "no-unmodified-loop-condition": "error", 36 | "no-unneeded-ternary": "error", 37 | "no-useless-return": "error", 38 | "object-curly-spacing": "error", 39 | "quotes": ["error", "single"], 40 | "semi": "error", 41 | "semi-spacing": "error", 42 | "space-before-blocks": "error", 43 | "space-before-function-paren": ["error", "never"], 44 | "space-in-parens": ["error", "never"], 45 | "space-infix-ops": "error", 46 | "space-unary-ops": "error" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | 3 | * **Be mindful of your language.** Any of the following behavior is unacceptable: 4 | * Offensive comments related to gender identity and expression, sexual orientation, race, ethnicity, language, neuro-type, size, ability, class, religion, culture, subculture, political opinion, age, skill level, occupation, or background 5 | * Threats of violence 6 | * Deliberate intimidation 7 | * Sexually explicit or violent material 8 | * Unwelcome sexual attention 9 | * Stalking or following 10 | * Or any other kinds of harassment 11 | 12 | Use your best judgment. If it will possibly make others uncomfortable, do not post it. 13 | 14 | * **Be respectful.** Disagreement is not an opportunity to attack someone else's thoughts or opinions. Although views may differ, remember to approach every situation with patience and care. 15 | * **Be considerate.** Think about how your contribution will affect others in the community. 16 | * **Be open minded.** Embrace new people and new ideas. Our community is continually evolving and we welcome positive change. 17 | 18 | If you believe someone is violating the code of conduct, we ask that you report it by emailing [covidtrends@professormoose.com](mailto:covidtrends@professormoose.com). Please include your name and a description of the incident, and we will get back to you ASAP. 19 | 20 | --- 21 | 22 | This Code of Conduct is based on [the Code of Conduct for the p5.js community](https://github.com/processing/p5.js/blob/master/CODE_OF_CONDUCT.md). 23 | 24 | This statement is licensed under a [Creative Commons license](https://creativecommons.org/licenses/by-sa/4.0/). Please feel free to share and remix with attribution. 25 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributor's Guide 2 | 3 | ### Goals 4 | 5 | Our goals for the website are accuracy, clarity, and usefulness at a glance. Our audience is people interested in COVID-19, i.e. the general public. When making decisions about features, we would like to make sure they are useful for the majority of our audience, and not just for those with a technical background. 6 | 7 | ### Contribute 8 | 9 | We’d like to be inclusive of all kinds of contributions, not just code contributions or pull requests. So [things like](https://allcontributors.org/docs/en/emoji-key) feedback, ideas, identifying issues, spotting bugs, creating tutorials, working on translations, and more. 10 | 11 | We aim to prioritize issues and pull requests that address (or intersect with) our [current milestones](https://github.com/aatishb/covidtrends/milestones). 12 | 13 | We’re using the [All Contributors bot](https://allcontributors.org/docs/en/bot/usage). If you’ve contributed in any way, we encourage you to add your name to the contributor’s list by commenting on an issue or pull request with: 14 | 15 | ``` 16 | @all-contributors add @your-github-username for contribution-type 17 | ``` 18 | where `contribution-type` is [one of these areas](https://allcontributors.org/docs/en/emoji-key). 19 | 20 | ### Move slow and fix things 21 | 22 | Because of the fairly large number of people currently using this as a resource (and the limited resources on our side as maintainers of this project), we would like to err on the side of thoroughness and stability, rather than moving fast to introduce new features that increase the complexity of the website. 23 | 24 | We expect to have development cycles on the order of weeks rather than days. The global community will be dealing with COVID-19 for months :worried: and we’d rather this be a reliable and trusted resource during that time. Plus, we are all working on this project part-time, and can only spend so many hours on this a week. 25 | 26 | ### When in doubt, ask first 27 | 28 | If you are planning to make a pull request and would be disappointed or upset if it is not merged, we encourage you to first suggest your idea on an issue, and wait to hear back before proceeding. 29 | 30 | ### Open source 31 | 32 | The codebase is open source, and we encourage anyone interested to create their own parallel branch with different data sources, features, translations, or whatever is important to you and your audience. We encourage you to fork this repository as you see fit. 33 | 34 | ### Quality over quantity 35 | 36 | We don’t want to become a repository of many datasets, as it’s difficult for us to vouch for their accuracy and reliability. For now we’d like to limit this to a small handful of comprehensive datasets that we understand well, and that would be helpful for the majority of our users. And we’d like to make it easier for people to fork this code and adapt it for their own datasets. 37 | 38 | ### Where I’m coming from 39 | 40 | Putting my cards on the table (@aatishb here): This is my first time co-managing an open source repository at this level of visibility. I’m an educator and not a professional web developer. This is a learning process for all of us, and I appreciate your patience and understanding as we learn together. 41 | 42 | ### Be nice 43 | 44 | Please assume the best intentions of anyone you communicate with here. As we’re all learning, communicating while being physically distant is hard! Please read our [Code of Conduct](CODE_OF_CONDUCT.md). If you see anyone violating these norms you can reach out to us directly at [covidtrends@professormoose.com](mailto:covidtrends@professormoose.com). 45 | 46 | 47 | Thanks all, and stay safe! 48 |
@aatishb & @mustpax 49 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | width: 100%; 3 | height: 100%; 4 | margin: 0; 5 | } 6 | 7 | body, 8 | .plotly-notifier { 9 | font-family: 'Open Sans', sans-serif; 10 | } 11 | 12 | body { 13 | font-size:1em; 14 | line-height: 1.5; 15 | font-weight: 400; 16 | color: #444; 17 | 18 | text-rendering: optimizeLegibility; 19 | } 20 | 21 | 22 | h1 { 23 | margin:0px; /* was 20 px */ 24 | /* 25 | text-align:center;*/ 26 | font-weight:100; 27 | font-size:2rem; 28 | } 29 | 30 | h2, 31 | .h2 { 32 | margin:0px; 33 | font-weight:700; 34 | font-size: 1.5rem; 35 | margin-bottom:1rem; 36 | } 37 | 38 | h3 { 39 | text-align:center; 40 | font-weight:400; 41 | font-size:1.2rem; 42 | } 43 | 44 | h1, h2, .h2, h3 { 45 | line-height: 1.1; 46 | } 47 | 48 | b { 49 | font-weight: bold; 50 | } 51 | 52 | i { 53 | font-style: italic; 54 | } 55 | 56 | p { 57 | font-size: 1rem; 58 | } 59 | 60 | .logowrapper { 61 | flex: 1; 62 | 63 | display: flex; 64 | flex-direction: column; 65 | align-items: center; 66 | justify-content: center; 67 | 68 | min-width: 10rem; 69 | } 70 | 71 | .logowrapper a { 72 | text-decoration: none; /* no underline */ 73 | color: white; 74 | } 75 | 76 | .logowrapper h1 { 77 | text-align: center; 78 | } 79 | 80 | .logos { 81 | margin-top:1rem; 82 | } 83 | 84 | .logos > a:first-child { 85 | margin-right: 0.75rem; 86 | } 87 | 88 | #root { 89 | height: 100%; 90 | display: flex; 91 | flex-direction: column; 92 | } 93 | 94 | #title { 95 | flex: 1; 96 | } 97 | 98 | header { 99 | color: white; 100 | background-image: linear-gradient(to bottom, #2c003e, #721b65); 101 | position: relative; 102 | display: flex; 103 | padding: 0.75rem; 104 | flex-shrink: 0 105 | } 106 | 107 | .explainer { 108 | flex: 6; 109 | padding-right: 2rem; 110 | text-align: left; 111 | } 112 | 113 | .explainer a { 114 | text-decoration: underline; 115 | color: lightgoldenrodyellow; 116 | cursor: pointer; 117 | } 118 | 119 | .explainer p { 120 | margin-top: 0.5rem; 121 | font-size: 0.9rem; 122 | } 123 | 124 | .explainer > p:first-child { 125 | margin-top: 0; 126 | } 127 | 128 | .ctapp { 129 | display: flex; 130 | flex-direction: row; 131 | flex-grow: 1; 132 | 133 | overflow-y: auto; 134 | -webkit-overflow-scrolling: touch; 135 | } 136 | 137 | .ctapp h2, 138 | .ctapp .h2 { 139 | color: #fe346e; 140 | } 141 | 142 | main { 143 | flex: 6; 144 | display: flex; 145 | flex-direction: column; 146 | padding: 1rem; 147 | } 148 | 149 | aside { 150 | flex: 1; 151 | 152 | display: flex; 153 | flex-direction: column; 154 | 155 | background-color: #fcf8e8; 156 | padding: 1rem; 157 | min-width: 10rem; 158 | 159 | overflow-y: auto; 160 | -webkit-overflow-scrolling: touch; 161 | } 162 | 163 | aside > div { 164 | margin-bottom: 2rem; 165 | } 166 | 167 | aside > div:last-child { 168 | margin-bottom: 0; 169 | } 170 | 171 | .countries { 172 | 173 | overflow-y: auto; 174 | -webkit-overflow-scrolling: touch; 175 | } 176 | 177 | aside h2 { 178 | font-size: 1.5rem; 179 | text-align: center; 180 | } 181 | 182 | footer { 183 | font-size: 0.75rem; 184 | } 185 | 186 | .nav { 187 | display: flex; 188 | flex-direction: row; 189 | } 190 | 191 | .navelement { 192 | padding: 1rem; 193 | text-align: center; 194 | margin: auto; 195 | } 196 | 197 | .navelement > h2 { 198 | margin-bottom: 0; 199 | margin: auto; 200 | } 201 | 202 | .slidercontainer { 203 | flex-grow: 1; 204 | } 205 | 206 | .slider { 207 | width: 100%; 208 | min-width: 200px; 209 | } 210 | 211 | svg { 212 | fill: #fe346e; 213 | } 214 | 215 | #hide { 216 | font-size: 1rem; 217 | padding: 0.5rem; 218 | position: absolute; 219 | bottom: 0; 220 | right: 0; 221 | } 222 | 223 | .search { 224 | width: 100%; 225 | display: flex; 226 | flex-direction: row; 227 | min-width: 10rem; 228 | } 229 | 230 | .search > input { 231 | flex: 1; 232 | font-size: 0.75rem; 233 | padding: 0.5rem; 234 | margin-top: 0.5rem; 235 | } 236 | 237 | .buttonwrapper { 238 | width: 100%; 239 | display:flex; 240 | flex-direction: row; 241 | flex-wrap: wrap; 242 | 243 | justify-content: space-between; 244 | } 245 | 246 | button { 247 | padding: 0.3rem; 248 | margin: auto; 249 | font-size: 1rem; 250 | 251 | text-align: center; 252 | text-decoration: none; 253 | 254 | transition-duration: 0.4s; 255 | 256 | background-color: #721b65; 257 | color: lightgoldenrodyellow; 258 | border: 0.125rem solid #721b65; 259 | border-radius: 0.25rem; 260 | } 261 | 262 | button:hover { 263 | background-color: rgb(69,10,76); 264 | border: 0.125rem solid rgb(69,10,76); 265 | color: lemonchiffon; 266 | } 267 | 268 | .countries button { 269 | margin-top: 0.5rem; 270 | } 271 | .countries p { 272 | margin-bottom: 0.75rem; 273 | } 274 | 275 | select { 276 | min-width: 12rem; 277 | font-size: 1rem; 278 | padding: 0.5rem; 279 | width: 100%; 280 | margin: 0.5rem 0; 281 | } 282 | 283 | select:first-child { 284 | margin-top: 0; 285 | } 286 | 287 | .nodata { 288 | height: 100%; 289 | display: flex; 290 | align-content: center; 291 | justify-content: center; 292 | align-items: center; 293 | } 294 | -------------------------------------------------------------------------------- /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "projectName": "covidtrends", 3 | "projectOwner": "aatishb", 4 | "repoType": "github", 5 | "repoHost": "https://github.com", 6 | "files": [ 7 | "README.md" 8 | ], 9 | "imageSize": 100, 10 | "commit": true, 11 | "commitConvention": "none", 12 | "contributors": [ 13 | { 14 | "login": "aatishb", 15 | "name": "Aatish Bhatia", 16 | "avatar_url": "https://avatars2.githubusercontent.com/u/1878638?v=4", 17 | "profile": "https://aatishb.com", 18 | "contributions": [ 19 | "code", 20 | "maintenance" 21 | ] 22 | }, 23 | { 24 | "login": "mustpax", 25 | "name": "Mustafa \"Moose\" Paksoy", 26 | "avatar_url": "https://avatars0.githubusercontent.com/u/22178?v=4", 27 | "profile": "http://www.professormoose.com", 28 | "contributions": [ 29 | "maintenance" 30 | ] 31 | }, 32 | { 33 | "name": "Henry Reich", 34 | "avatar_url": "https://static1.squarespace.com/static/57c4aa39725e25ba4eb3ace1/t/57c4aeac20099e3efb1bf1c9/1583766666685/?format=1500w", 35 | "profile": "http://www.youtube.com/minutephysics", 36 | "contributions": [ 37 | "ideas" 38 | ] 39 | }, 40 | { 41 | "login": "byteit101", 42 | "name": "Patrick Plenefisch", 43 | "avatar_url": "https://avatars0.githubusercontent.com/u/577344?v=4", 44 | "profile": "https://github.com/byteit101", 45 | "contributions": [ 46 | "code" 47 | ] 48 | }, 49 | { 50 | "login": "edg2s", 51 | "name": "Ed S", 52 | "avatar_url": "https://avatars3.githubusercontent.com/u/180672?v=4", 53 | "profile": "https://github.com/edg2s", 54 | "contributions": [ 55 | "code", 56 | "tool" 57 | ] 58 | }, 59 | { 60 | "login": "exclipy", 61 | "name": "exclipy", 62 | "avatar_url": "https://avatars1.githubusercontent.com/u/508799?v=4", 63 | "profile": "https://github.com/exclipy", 64 | "contributions": [ 65 | "code" 66 | ] 67 | }, 68 | { 69 | "login": "saufrecht", 70 | "name": "S Aufrecht", 71 | "avatar_url": "https://avatars3.githubusercontent.com/u/43078751?v=4", 72 | "profile": "https://aufrecht.org", 73 | "contributions": [ 74 | "doc" 75 | ] 76 | }, 77 | { 78 | "login": "neon-ninja", 79 | "name": "Nick Young", 80 | "avatar_url": "https://avatars1.githubusercontent.com/u/3378822?v=4", 81 | "profile": "https://github.com/neon-ninja", 82 | "contributions": [ 83 | "code" 84 | ] 85 | }, 86 | { 87 | "login": "NeverFearTheasHere", 88 | "name": "Thea Lanherne", 89 | "avatar_url": "https://avatars1.githubusercontent.com/u/12138621?v=4", 90 | "profile": "https://github.com/NeverFearTheasHere", 91 | "contributions": [ 92 | "bug" 93 | ] 94 | }, 95 | { 96 | "login": "arjo129", 97 | "name": "Arjo Chakravarty", 98 | "avatar_url": "https://avatars0.githubusercontent.com/u/542272?v=4", 99 | "profile": "https://github.com/arjo129", 100 | "contributions": [ 101 | "code" 102 | ] 103 | }, 104 | { 105 | "name": "Lucy Xu", 106 | "avatar_url": "https://pbs.twimg.com/profile_images/665771785493712896/cwYcvRLp_400x400.jpg", 107 | "profile": "https://twitter.com/lucypxu", 108 | "contributions": [ 109 | "question" 110 | ] 111 | }, 112 | { 113 | "login": "bdarfler", 114 | "name": "Ben Darfler", 115 | "avatar_url": "https://avatars1.githubusercontent.com/u/197776?v=4", 116 | "profile": "http://bdarfler.com", 117 | "contributions": [ 118 | "code" 119 | ] 120 | }, 121 | { 122 | "login": "waldyrious", 123 | "name": "Waldir Pimenta", 124 | "avatar_url": "https://avatars2.githubusercontent.com/u/478237?v=4", 125 | "profile": "https://zmoazeni.github.io/gitspective/#/timeline/waldyrious", 126 | "contributions": [ 127 | "review" 128 | ] 129 | }, 130 | { 131 | "login": "Kojoley", 132 | "name": "Nikita Kniazev", 133 | "avatar_url": "https://avatars3.githubusercontent.com/u/2743474?v=4", 134 | "profile": "https://github.com/Kojoley", 135 | "contributions": [ 136 | "design" 137 | ] 138 | }, 139 | { 140 | "login": "thisIsTheFoxe", 141 | "name": "Henry", 142 | "avatar_url": "https://avatars0.githubusercontent.com/u/18512366?v=4", 143 | "profile": "https://www.thisisthefoxe.me", 144 | "contributions": [ 145 | "content" 146 | ] 147 | }, 148 | { 149 | "login": "rpkoller", 150 | "name": "Ralf Koller", 151 | "avatar_url": "https://avatars2.githubusercontent.com/u/1665422?v=4", 152 | "profile": "https://github.com/rpkoller", 153 | "contributions": [ 154 | "code", 155 | "review", 156 | "a11y" 157 | ] 158 | }, 159 | { 160 | "login": "joachimneumann", 161 | "name": "Joachim Neumann", 162 | "avatar_url": "https://avatars1.githubusercontent.com/u/5642225?v=4", 163 | "profile": "http://joachimneumann.com", 164 | "contributions": [ 165 | "bug" 166 | ] 167 | }, 168 | { 169 | "name": "Arkarup Banerjee", 170 | "avatar_url": "all-contributors-photos/arkarup.jpg", 171 | "profile": "https://www.arkarup.com/", 172 | "contributions": [ 173 | "ideas" 174 | ] 175 | }, 176 | { 177 | "name": "Ann Bybee-Finley", 178 | "avatar_url": "all-contributors-photos/bybee-finley.jpg", 179 | "profile": "https://blogs.cornell.edu/scslab/people/275-2/", 180 | "contributions": [ 181 | "ideas" 182 | ] 183 | }, 184 | { 185 | "name": "Connie Sun", 186 | "avatar_url": "all-contributors-photos/connie.jpg", 187 | "profile": "https://www.instagram.com/cartoonconnie/", 188 | "contributions": [ 189 | "design" 190 | ] 191 | }, 192 | { 193 | "name": "Upasana Roy", 194 | "avatar_url": "https://pbs.twimg.com/profile_images/798378170764394496/2i4v4w6E_400x400.jpg", 195 | "profile": "https://twitter.com/roy_upasana", 196 | "contributions": [ 197 | "ideas", 198 | "design" 199 | ] 200 | }, 201 | { 202 | "login": "archiewood", 203 | "name": "archiewood", 204 | "avatar_url": "https://avatars0.githubusercontent.com/u/58074498?v=4", 205 | "profile": "https://github.com/archiewood", 206 | "contributions": [ 207 | "ideas" 208 | ] 209 | }, 210 | { 211 | "login": "reaganch", 212 | "name": "Reagan Chandramohan", 213 | "avatar_url": "https://avatars1.githubusercontent.com/u/14113814?v=4", 214 | "profile": "https://reaganc.bitbucket.io", 215 | "contributions": [ 216 | "bug" 217 | ] 218 | }, 219 | { 220 | "login": "CharsiBabu", 221 | "name": "CharsiBabu", 222 | "avatar_url": "https://avatars2.githubusercontent.com/u/4214491?v=4", 223 | "profile": "https://github.com/CharsiBabu", 224 | "contributions": [ 225 | "code" 226 | ] 227 | }, 228 | { 229 | "login": "MrSpiffyClean", 230 | "name": "Ricardo Gonçalves", 231 | "avatar_url": "https://avatars3.githubusercontent.com/u/63736648?v=4", 232 | "profile": "https://github.com/MrSpiffyClean", 233 | "contributions": [ 234 | "code" 235 | ] 236 | }, 237 | { 238 | "login": "bchurchill", 239 | "name": "Berkeley Churchill", 240 | "avatar_url": "https://avatars0.githubusercontent.com/u/640745?v=4", 241 | "profile": "http://www.berkeleychurchill.com", 242 | "contributions": [ 243 | "code" 244 | ] 245 | } 246 | ], 247 | "contributorsPerLine": 7, 248 | "skipCi": true 249 | } 250 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Covid Trends 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 |

This interactive charts the new {{selectedData.toLowerCase()}} of COVID-19 in the past week vs. the total {{selectedData.toLowerCase()}} to date. When plotted in this way, exponential growth is represented as a straight line that slopes upwards. Notice that almost all countries follow a very similar path of exponential growth. We're all in this together. Learn more.

34 | 35 | 36 | 37 |

To learn more about this graph, watch this video created by Minute Physics.

38 |
39 | 40 | 41 | 42 |

Note: The x-axis of this graph is not time, but is instead the total number of cases or deaths.

43 | 44 |

Tips: Press Space (or the play button) to Play/Pause. Press +/- keys (or drag the slider) to see daily changes. Hover over the graph for more info. Drag your mouse to zoom in, doubleclick to zoom back out. And don't forget to wash your hands!

45 | 46 | Hide 47 |
48 |
49 | 50 |
51 | 52 |

Covid Trends

53 | 54 |
55 | Avatar of Aatish Bhatia 56 | Minute Physics Logo 57 |
58 | 59 |
60 | 61 |
62 | 63 |
64 | 65 |
66 | 67 | 68 | 69 | 93 | 94 |
Not enough data for these parameters.
95 |
Please select some {{regionType.toLowerCase()}} to display.
96 | 97 | 100 | 101 |
102 | 103 | 162 | 163 |
164 | 165 |
166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## What is this? 2 | 3 | [![All Contributors](https://img.shields.io/badge/all_contributors-25-orange.svg?style=flat-square)](#contributors-) 4 | 5 | 6 | This is an [interactive graph / animation](https://aatishb.com/covidtrends/) that charts the trajectory of global COVID-19 cases. 7 | 8 | The graph plots the number of new confirmed cases in the past week, versus the total number of confirmed cases. 9 | 10 | When plotted in this way, exponential growth is displayed as a straight line. 11 | 12 | Notice that most countries follow a similar straight line path, indicating that the growth rate is similar across countries. We're all in this together. 13 | 14 | **Tips:** Press Space (or the play button) to Play/Pause. Press +/- keys (or the slider) to see daily changes. Hover over the graph for more info. Drag cursor to zoom into graph, double-click to zoom back out. Use dropdown menus to switch between Confirmed Cases ↔ Deaths, between regions, or between a logarithmic ↔ linear scale. And don't forget to wash your hands! 15 | 16 | ## Credits 17 | 18 | This interactive pulls data on COVID-19 provided by [Johns Hopkins CSSE](https://github.com/CSSEGISandData/COVID-19) and NYTimes. Huge thanks to them for making this invaluable data source publicly available. 19 | 20 | Created by [Aatish Bhatia](https://aatishb.com/) in collaboration with [Henry Reich](https://www.youtube.com/user/minutephysics). 21 | 22 | Created using [Plotly.js](https://plot.ly/javascript/) and [Vue.js](https://vuejs.org/) 23 | 24 | ## Contributors ✨ 25 | 26 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 |

Aatish Bhatia

💻 🚧

Mustafa "Moose" Paksoy

🚧

Henry Reich

🤔

Patrick Plenefisch

💻

Ed S

💻 🔧

exclipy

💻

S Aufrecht

📖

Nick Young

💻

Thea Lanherne

🐛

Arjo Chakravarty

💻

Lucy Xu

💬

Ben Darfler

💻

Waldir Pimenta

👀

Nikita Kniazev

🎨

Henry

🖋

Ralf Koller

💻 👀 ️️️️♿️

Joachim Neumann

🐛

Arkarup Banerjee

🤔

Ann Bybee-Finley

🤔

Connie Sun

🎨

Upasana Roy

🤔 🎨

archiewood

🤔

Reagan Chandramohan

🐛

CharsiBabu

💻

Ricardo Gonçalves

💻

Berkeley Churchill

💻
67 | 68 | 69 | 70 | 71 | 72 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 73 | 74 | Special thanks to Ritwick Ghosh, Nicky Case, Shekhar Bhatia, and Igor Kholopov for their very helpful feedback & suggestions! 75 | 76 | ## Participate and Contribute 77 | 78 | If you would like to participate or contribute, please read our [Contributor's Guide](CONTRIBUTING.md) and [Code of Conduct](CODE_OF_CONDUCT.md). 79 | 80 | ## License 81 | 82 | Code in this repository which is not otherwise licensed is licensed under the MIT License; see [LICENSE.txt](LICENSE.txt) for complete text. 83 | 84 | This repository pulls data from [2019 Novel Coronavirus COVID-19 (2019-nCoV) Data Repository by Johns Hopkins CSSE](https://github.com/CSSEGISandData/COVID-19) and [New York Times Coronavirus (Covid-19) Data in the United States](https://github.com/nytimes/covid-19-data#license-and-attribution). Please consult these repositories for terms of use on the data. 85 | 86 | -------------------------------------------------------------------------------- /vue-definitions.js: -------------------------------------------------------------------------------- 1 | // custom graph component 2 | Vue.component('graph', { 3 | 4 | props: ['graphData', 'day', 'resize'], 5 | 6 | template: '
', 7 | 8 | methods: { 9 | 10 | mountGraph() { 11 | 12 | Plotly.newPlot(this.$refs.graph, [], {}, {responsive: true}); 13 | 14 | this.$refs.graph.on('plotly_hover', this.onHoverOn) 15 | .on('plotly_unhover', this.onHoverOff) 16 | .on('plotly_relayout', this.onLayoutChange); 17 | 18 | }, 19 | 20 | onHoverOn(data) { 21 | 22 | let curveNumber = data.points[0].curveNumber; 23 | let name = this.graphData.traces[curveNumber].name; 24 | 25 | if (name) { 26 | 27 | this.traceIndices = this.graphData.traces.map((e, i) => e.name == name ? i : -1).filter(e => e >= 0); 28 | let update = {'line': {color: 'rgba(254, 52, 110, 1)'}}; 29 | 30 | for (let i of this.traceIndices) { 31 | Plotly.restyle(this.$refs.graph, update, [i]); 32 | } 33 | } 34 | 35 | }, 36 | 37 | onHoverOff() { 38 | 39 | let update = {'line': {color: 'rgba(0,0,0,0.15)'}}; 40 | 41 | for (let i of this.traceIndices) { 42 | Plotly.restyle(this.$refs.graph, update, [i]); 43 | } 44 | 45 | }, 46 | 47 | onLayoutChange(data) { 48 | 49 | this.emitGraphAttributes(); 50 | 51 | // if the user selects autorange, go back to the default range 52 | if (data['xaxis.autorange'] == true || data['yaxis.autorange'] == true) { 53 | this.userSetRange = false; 54 | this.updateGraph(); 55 | } 56 | 57 | // if the user selects a custom range, use this 58 | else if (data['xaxis.range[0]']) { 59 | this.xrange = [data['xaxis.range[0]'], data['xaxis.range[1]']].map(e => parseFloat(e)); 60 | this.yrange = [data['yaxis.range[0]'], data['yaxis.range[1]']].map(e => parseFloat(e)); 61 | this.userSetRange = true; 62 | } 63 | 64 | }, 65 | 66 | updateGraph() { 67 | 68 | // we're deep copying the layout object to avoid side effects 69 | // because plotly mutates layout on user input 70 | // note: this may cause issues if we pass in date objects through the layout 71 | let layout = JSON.parse(JSON.stringify(this.graphData.layout)); 72 | 73 | // if the user selects a custom range, use it 74 | if (this.userSetRange) { 75 | layout.xaxis.range = this.xrange; 76 | layout.yaxis.range = this.yrange; 77 | } 78 | 79 | Plotly.react(this.$refs.graph, this.graphData.traces, layout, this.graphData.config); 80 | 81 | }, 82 | 83 | calculateAngle() { 84 | if (this.graphData.uistate.showTrendLine && this.graphData.uistate.doublingTime > 0) { 85 | let element = this.$refs.graph.querySelector('.cartesianlayer').querySelector('.plot').querySelector('.scatterlayer').lastChild.querySelector('.lines').firstChild.getAttribute('d'); 86 | let pts = element.split('M').join(',').split('L').join(',').split(',').filter(e => e != ''); 87 | let angle = Math.atan2(pts[3] - pts[1], pts[2] - pts[0]); 88 | return angle; 89 | } else { 90 | return NaN; 91 | } 92 | }, 93 | 94 | emitGraphAttributes() { 95 | let graphOuterDiv = this.$refs.graph.querySelector('.main-svg').attributes; 96 | this.$emit('update:width', graphOuterDiv.width.nodeValue); 97 | this.$emit('update:height', graphOuterDiv.height.nodeValue); 98 | 99 | let graphInnerDiv = this.$refs.graph.querySelector('.xy').firstChild.attributes; 100 | this.$emit('update:innerWidth', graphInnerDiv.width.nodeValue); 101 | this.$emit('update:innerHeight', graphInnerDiv.height.nodeValue); 102 | this.$emit('update:referenceLineAngle', this.calculateAngle()); 103 | } 104 | 105 | }, 106 | 107 | mounted() { 108 | this.mountGraph(); 109 | 110 | if (this.graphData) { 111 | this.updateGraph(); 112 | } 113 | 114 | this.emitGraphAttributes(); 115 | this.$emit('update:mounted', true); 116 | 117 | }, 118 | 119 | watch: { 120 | 121 | graphData: { 122 | 123 | deep: true, 124 | 125 | handler(data, oldData) { 126 | 127 | // if UI state changes, revert to auto range 128 | if (JSON.stringify(data.uistate) != JSON.stringify(oldData.uistate)) { 129 | this.userSetRange = false; 130 | } 131 | 132 | this.updateGraph(); 133 | this.$emit('update:referenceLineAngle', this.calculateAngle()); 134 | 135 | } 136 | 137 | }, 138 | 139 | resize() { 140 | Plotly.Plots.resize(this.$refs.graph); 141 | }, 142 | 143 | }, 144 | 145 | data() { 146 | return { 147 | xrange: [], // stores user selected xrange 148 | yrange: [], // stores user selected yrange 149 | userSetRange: false, // determines whether to use user selected range 150 | traceIndices: [], 151 | }; 152 | } 153 | 154 | }); 155 | 156 | // global data 157 | window.app = new Vue({ 158 | 159 | el: '#root', 160 | 161 | mounted() { 162 | this.pullData(this.selectedData, this.selectedRegion); 163 | }, 164 | 165 | created: function() { 166 | 167 | let url = window.location.href.split('?'); 168 | 169 | if (url.length > 1) { 170 | 171 | let urlParameters = new URLSearchParams(url[1]); 172 | 173 | if (urlParameters.has('scale')) { 174 | 175 | let myScale = urlParameters.get('scale').toLowerCase(); 176 | 177 | if (myScale == 'log') { 178 | this.selectedScale = 'Logarithmic Scale'; 179 | } else if (myScale == 'linear') { 180 | this.selectedScale = 'Linear Scale'; 181 | } 182 | } 183 | 184 | if (urlParameters.has('data')) { 185 | let myData = urlParameters.get('data').toLowerCase(); 186 | if (myData == 'cases') { 187 | this.selectedData = 'Confirmed Cases'; 188 | } else if (myData == 'deaths') { 189 | this.selectedData = 'Reported Deaths'; 190 | } 191 | 192 | } 193 | 194 | if (urlParameters.has('region')) { 195 | let myRegion = urlParameters.get('region'); 196 | if (this.regions.includes(myRegion)) { 197 | this.selectedRegion = myRegion; 198 | } 199 | } 200 | 201 | // since this rename came later, use the old name to not break existing URLs 202 | let renames = { 203 | 'China': 'China (Mainland)' 204 | }; 205 | 206 | // before we added regions, the url parameter was called country instead of location 207 | // we still check for this so as to not break existing URLs 208 | if (urlParameters.has('country')) { 209 | this.selectedCountries = urlParameters.getAll('country').map(e => Object.keys(renames).includes(e) ? renames[e] : e); 210 | } else if (urlParameters.has('location')) { 211 | this.selectedCountries = urlParameters.getAll('location').map(e => Object.keys(renames).includes(e) ? renames[e] : e); 212 | } 213 | 214 | if (urlParameters.has('trendline')) { 215 | let showTrendLine = urlParameters.get('trendline'); 216 | this.showTrendLine = (showTrendLine == 'true'); 217 | } else if (urlParameters.has('doublingtime')) { 218 | let doublingTime = urlParameters.get('doublingtime'); 219 | this.doublingTime = doublingTime; 220 | } 221 | 222 | if (urlParameters.has('select')) { 223 | this.mySelect = urlParameters.get('select').toLowerCase(); 224 | } 225 | 226 | } 227 | 228 | window.addEventListener('keydown', e => { 229 | 230 | if ((e.key == ' ') && this.dates.length > 0) { 231 | this.play(); 232 | } 233 | 234 | else if ((e.key == '-' || e.key == '_') && this.dates.length > 0) { 235 | this.paused = true; 236 | this.day = Math.max(this.day - 1, this.minDay); 237 | } 238 | 239 | else if ((e.key == '+' || e.key == '=') && this.dates.length > 0) { 240 | this.paused = true; 241 | this.day = Math.min(this.day + 1, this.dates.length); 242 | } 243 | 244 | }); 245 | 246 | }, 247 | 248 | watch: { 249 | selectedData() { 250 | if (!this.firstLoad) { 251 | this.pullData(this.selectedData, this.selectedRegion, /*updateSelectedCountries*/ false); 252 | } 253 | this.searchField = ''; 254 | }, 255 | 256 | selectedRegion() { 257 | if (!this.firstLoad) { 258 | this.pullData(this.selectedData, this.selectedRegion, /*updateSelectedCountries*/ true); 259 | } 260 | this.searchField = ''; 261 | }, 262 | 263 | minDay() { 264 | if (this.day < this.minDay) { 265 | this.day = this.minDay; 266 | } 267 | }, 268 | 269 | 'graphAttributes.mounted': function() { 270 | 271 | if (this.graphAttributes.mounted && this.autoplay && this.minDay > 0) { 272 | this.day = this.minDay; 273 | this.play(); 274 | this.autoplay = false; // disable autoplay on first play 275 | } 276 | }, 277 | 278 | searchField() { 279 | let debouncedSearch = this.debounce(this.search, 250, false); 280 | debouncedSearch(); 281 | } 282 | }, 283 | 284 | methods: { 285 | 286 | debounce(func, wait, immediate) { // https://davidwalsh.name/javascript-debounce-function 287 | var timeout; 288 | return function() { 289 | var context = this, args = arguments; 290 | var later = function() { 291 | timeout = null; 292 | if (!immediate) func.apply(context, args); 293 | }; 294 | var callNow = immediate && !timeout; 295 | clearTimeout(timeout); 296 | timeout = setTimeout(later, wait); 297 | if (callNow) func.apply(context, args); 298 | }; 299 | }, 300 | 301 | myMax() { // https://stackoverflow.com/a/12957522 302 | var par = []; 303 | for (var i = 0; i < arguments.length; i++) { 304 | if (!isNaN(arguments[i])) { 305 | par.push(arguments[i]); 306 | } 307 | } 308 | return Math.max.apply(Math, par); 309 | }, 310 | 311 | myMin() { 312 | var par = []; 313 | for (var i = 0; i < arguments.length; i++) { 314 | if (!isNaN(arguments[i])) { 315 | par.push(arguments[i]); 316 | } 317 | } 318 | return Math.min.apply(Math, par); 319 | }, 320 | 321 | pullData(selectedData, selectedRegion, updateSelectedCountries = true) { 322 | 323 | if (selectedRegion != 'US') { 324 | let url; 325 | if (selectedData == 'Confirmed Cases') { 326 | url = 'https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv'; 327 | } else if (selectedData == 'Reported Deaths') { 328 | url = 'https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_deaths_global.csv'; 329 | } else { 330 | return; 331 | } 332 | Plotly.d3.csv(url, (data) => this.processData(data, selectedRegion, updateSelectedCountries)); 333 | } else { // selectedRegion == 'US' 334 | const type = (selectedData == 'Reported Deaths') ? 'deaths' : 'cases'; 335 | const url = 'https://raw.githubusercontent.com/nytimes/covid-19-data/master/us-states.csv'; 336 | Plotly.d3.csv(url, (data) => this.processData(this.preprocessNYTData(data, type), selectedRegion, updateSelectedCountries)); 337 | } 338 | }, 339 | 340 | removeRepeats(array) { 341 | return [...new Set(array)]; 342 | }, 343 | 344 | groupByCountry(data, dates, regionsToPullToCountryLevel /* pulls out Hong Kong & Macau from region to country level */) { 345 | 346 | let countries = data.map(e => e['Country/Region']); 347 | countries = this.removeRepeats(countries); 348 | 349 | let grouped = []; 350 | for (let country of countries) { 351 | 352 | // filter data for this country (& exclude regions we're pulling to country level) 353 | // e.g. Mainland China numbers should not include Hong Kong & Macau, to avoid double counting 354 | let countryData = data.filter(e => e['Country/Region'] == country) 355 | .filter(e => !regionsToPullToCountryLevel.includes(e['Province/State'])); 356 | 357 | const row = {region: country}; 358 | 359 | for (let date of dates) { 360 | let sum = countryData.map(e => parseInt(e[date]) || 0).reduce((a, b) => a + b); 361 | row[date] = sum; 362 | } 363 | 364 | grouped.push(row); 365 | 366 | } 367 | 368 | return grouped; 369 | }, 370 | 371 | filterByCountry(data, dates, selectedRegion) { 372 | return data.filter(e => e['Country/Region'] == selectedRegion) 373 | .map(e => Object.assign({}, e, {region: e['Province/State']})); 374 | }, 375 | 376 | convertStateToCountry(data, dates, selectedRegion) { 377 | return data.filter(e => e['Province/State'] == selectedRegion) 378 | .map(e => Object.assign({}, e, {region: e['Province/State']})); 379 | }, 380 | 381 | processData(data, selectedRegion, updateSelectedCountries) { 382 | let dates = Object.keys(data[0]).slice(4); 383 | this.dates = dates; 384 | this.day = this.dates.length; 385 | 386 | let regionsToPullToCountryLevel = ['Hong Kong', 'Macau']; 387 | 388 | let grouped; 389 | 390 | if (selectedRegion == 'World') { 391 | grouped = this.groupByCountry(data, dates, regionsToPullToCountryLevel); 392 | 393 | // pull Hong Kong and Macau to Country level 394 | for (let region of regionsToPullToCountryLevel) { 395 | let country = this.convertStateToCountry(data, dates, region); 396 | if (country.length === 1) { 397 | grouped = grouped.concat(country); 398 | } 399 | } 400 | 401 | } else { 402 | grouped = this.filterByCountry(data, dates, selectedRegion) 403 | .filter(e => !regionsToPullToCountryLevel.includes(e.region)); // also filter our Hong Kong and Macau as subregions of Mainland China 404 | } 405 | 406 | let exclusions = ['Cruise Ship', 'Diamond Princess']; 407 | 408 | let renames = { 409 | 'Taiwan*': 'Taiwan', 410 | 'Korea, South': 'South Korea', 411 | 'China': 'China (Mainland)' 412 | }; 413 | 414 | let covidData = []; 415 | for (let row of grouped) { 416 | 417 | if (!exclusions.includes(row.region)) { 418 | const arr = []; 419 | for (let date of dates) { 420 | arr.push(row[date]); 421 | } 422 | let slope = arr.map((e, i, a) => e - a[i - this.lookbackTime]); 423 | let region = row.region; 424 | 425 | if (Object.keys(renames).includes(region)) { 426 | region = renames[region]; 427 | } 428 | 429 | const cases = arr.map(e => e >= this.minCasesInCountry ? e : NaN); 430 | covidData.push({ 431 | country: region, 432 | cases, 433 | slope: slope.map((e, i) => arr[i] >= this.minCasesInCountry ? e : NaN), 434 | maxCases: this.myMax(...cases) 435 | }); 436 | 437 | } 438 | } 439 | 440 | this.covidData = covidData.filter(e => e.maxCases > this.minCasesInCountry); 441 | this.countries = this.covidData.map(e => e.country).sort(); 442 | this.visibleCountries = this.countries; 443 | const topCountries = this.covidData.sort((a, b) => b.maxCases - a.maxCases).slice(0, 9).map(e => e.country); 444 | const notableCountries = ['China (Mainland)', 'India', 'US', // Top 3 by population 445 | 'South Korea', 'Japan', 'Taiwan', 'Singapore', // Observed success so far 446 | 'Hong Kong', // Was previously included in China's numbers 447 | 'Canada', 'Australia']; // These appear in the region selector 448 | 449 | // TODO: clean this logic up later 450 | // expected behavior: generate/overwrite selected locations if: 1. data loaded from URL, but no selected locations are loaded. 2. data refreshed (e.g. changing region) 451 | // but do not overwrite selected locations if 1. selected locations loaded from URL. 2. We switch between confirmed cases <-> deaths 452 | if ((this.selectedCountries.length === 0 || !this.firstLoad) && updateSelectedCountries) { 453 | this.selectedCountries = this.countries.filter(e => topCountries.includes(e) || notableCountries.includes(e)); 454 | 455 | this.defaultCountries = this.selectedCountries; // Used for createURL default check 456 | 457 | if (this.mySelect == 'all') { 458 | this.selectedCountries = this.countries; 459 | } else if (this.mySelect == 'none') { 460 | this.selectedCountries = []; 461 | } 462 | this.mySelect = ''; 463 | 464 | } 465 | 466 | this.firstLoad = false; 467 | this.createURL(); 468 | }, 469 | 470 | preprocessNYTData(data, type) { 471 | let recastData = {}; 472 | data.forEach(e => { 473 | let st = recastData[e.state] = (recastData[e.state] || {'Province/State': e.state, 'Country/Region': 'US', 'Lat': null, 'Long': null}); 474 | st[fixNYTDate(e.date)] = parseInt(e[type]); 475 | }); 476 | return Object.values(recastData); 477 | 478 | function fixNYTDate(date) { 479 | let tmp = date.split('-'); 480 | return `${tmp[1]}/${tmp[2]}/${tmp[0].substr(2)}`; 481 | } 482 | }, 483 | 484 | formatDate(date) { 485 | if (!date) { 486 | return ''; 487 | } 488 | 489 | let [m, d, y] = date.split('/'); 490 | return new Date(Date.UTC(2000 + (+y), m - 1, d)).toISOString().slice(0, 10); 491 | }, 492 | 493 | dateToText(date) { 494 | if (!date) { 495 | return ''; 496 | } 497 | 498 | const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; 499 | 500 | let [m, d] = date.split('/'); 501 | return monthNames[m - 1] + ' ' + d; 502 | }, 503 | 504 | // TODO: clean up play/pause logic 505 | play() { 506 | if (this.paused) { 507 | 508 | if (this.day == this.dates.length) { 509 | this.day = this.minDay; 510 | } 511 | 512 | this.paused = false; 513 | setTimeout(this.increment, 200); 514 | 515 | } else { 516 | this.paused = true; 517 | } 518 | 519 | }, 520 | 521 | pause() { 522 | if (!this.paused) { 523 | this.paused = true; 524 | } 525 | }, 526 | 527 | increment() { 528 | 529 | if (this.day == this.dates.length || this.minDay < 0) { 530 | this.day = this.dates.length; 531 | this.paused = true; 532 | } 533 | else if (this.day < this.dates.length) { 534 | if (!this.paused) { 535 | this.day++; 536 | setTimeout(this.increment, 200); 537 | } 538 | } 539 | 540 | }, 541 | 542 | search() { 543 | this.visibleCountries = this.countries.filter(e => e.toLowerCase().includes(this.searchField.toLowerCase())); 544 | }, 545 | 546 | selectAll() { 547 | this.selectedCountries = this.countries; 548 | this.createURL(); 549 | }, 550 | 551 | deselectAll() { 552 | this.selectedCountries = []; 553 | this.createURL(); 554 | }, 555 | 556 | toggleHide() { 557 | this.isHidden = !this.isHidden; 558 | }, 559 | 560 | createURL() { 561 | 562 | let queryUrl = new URLSearchParams(); 563 | 564 | if (this.selectedScale == 'Linear Scale') { 565 | queryUrl.append('scale', 'linear'); 566 | } 567 | 568 | if (this.selectedData == 'Reported Deaths') { 569 | queryUrl.append('data', 'deaths'); 570 | } 571 | 572 | if (this.selectedRegion != 'World') { 573 | queryUrl.append('region', this.selectedRegion); 574 | } 575 | 576 | // since this rename came later, use the old name for URLs to avoid breaking existing URLs 577 | let renames = {'China (Mainland)': 'China'}; 578 | 579 | if (!this.showTrendLine) { 580 | queryUrl.append('trendline', this.showTrendLine); 581 | } 582 | 583 | else if (this.doublingTime != 2) { 584 | queryUrl.append('doublingtime', this.doublingTime); 585 | } 586 | 587 | // check if no countries selected 588 | // edge case: since selectedCountries may be larger than the country list (e.g. when switching from Confirmed Cases to Deaths), we can't simply check if selectedCountries is empty 589 | // so instead we check if the countries list does not include any of the selected countries 590 | if (!this.countries.some(country => this.selectedCountries.includes(country))) { 591 | queryUrl.append('select', 'none'); 592 | } 593 | 594 | // check if all countries selected 595 | // edge case: since selectedCountries may be larger than the country list (e.g. when switching from Confirmed Cases to Deaths), we can't simply compare array contents 596 | // so instead we check if the countries list is a proper subset of selectedCountries 597 | else if (this.countries.every(country => this.selectedCountries.includes(country))) { 598 | queryUrl.append('select', 'all'); 599 | } 600 | 601 | // else check if selection is different from default countries 602 | else if (JSON.stringify(this.selectedCountries.sort()) !== JSON.stringify(this.defaultCountries)) { 603 | 604 | // only append to URL the selected countries that are also in the currently displayed country list 605 | // this is done because of the edge case where selectedCountries may be larger than the country list (e.g. when switching from Confirmed Cases to Deaths) 606 | let countriesToAppendToUrl = this.selectedCountries.filter(e => this.countries.includes(e)); 607 | 608 | // apply renames and append to queryUrl 609 | countriesToAppendToUrl = countriesToAppendToUrl.map(country => Object.keys(renames).includes(country) ? renames[country] : country); 610 | countriesToAppendToUrl.forEach(country => queryUrl.append('location', country)); 611 | } 612 | 613 | if (queryUrl.toString() == '') { 614 | window.history.replaceState({}, 'Covid Trends', location.pathname); 615 | } else { 616 | window.history.replaceState({}, 'Covid Trends', '?' + queryUrl.toString()); 617 | } 618 | 619 | }, 620 | 621 | // reference line for exponential growth with a given doubling time 622 | referenceLine(x) { 623 | return x * (1 - Math.pow(2, -this.lookbackTime / this.doublingTime)); 624 | } 625 | 626 | }, 627 | 628 | computed: { 629 | 630 | filteredCovidData() { 631 | return this.covidData.filter(e => this.selectedCountries.includes(e.country)); 632 | }, 633 | 634 | minDay() { 635 | let minDay = this.myMin(...(this.filteredCovidData.map(e => e.slope.findIndex(f => f > 0)).filter(x => x != -1))); 636 | if (isFinite(minDay) && !isNaN(minDay)) { 637 | return minDay + 1; 638 | } else { 639 | return -1; 640 | } 641 | }, 642 | 643 | regionType() { 644 | switch (this.selectedRegion) { 645 | case 'World': 646 | return 'Countries'; 647 | case 'Australia': 648 | case 'US': 649 | return 'States / Territories'; 650 | case 'China': 651 | return 'Provinces'; 652 | case 'Canada': 653 | return 'Provinces'; 654 | default: 655 | return 'Regions'; 656 | } 657 | }, 658 | 659 | annotations() { 660 | 661 | return [{ 662 | visible: this.showTrendLine && this.doublingTime > 0, 663 | x: this.xAnnotation, 664 | y: this.yAnnotation, 665 | xref: 'x', 666 | yref: 'y', 667 | xshift: -50 * Math.cos(this.graphAttributes.referenceLineAngle), 668 | yshift: 50 * Math.sin(this.graphAttributes.referenceLineAngle), 669 | text: this.doublingTime + ' Day Doubling Time
of ' + this.selectedData, 670 | align: 'right', 671 | showarrow: false, 672 | textangle: this.graphAttributes.referenceLineAngle * 180 / Math.PI, 673 | font: { 674 | family: 'Open Sans, sans-serif', 675 | color: 'black', 676 | size: 14 677 | }, 678 | }]; 679 | 680 | }, 681 | 682 | layout() { 683 | return { 684 | title: 'Trajectory of ' + this.selectedRegion + ' COVID-19 ' + this.selectedData + ' (' + this.formatDate(this.dates[this.day - 1]) + ')', 685 | showlegend: false, 686 | autorange: false, 687 | xaxis: { 688 | title: 'Total ' + this.selectedData, 689 | type: this.selectedScale == 'Logarithmic Scale' ? 'log' : 'linear', 690 | range: this.selectedScale == 'Logarithmic Scale' ? this.logxrange : this.linearxrange, 691 | titlefont: { 692 | size: 24, 693 | color: 'rgba(254, 52, 110,1)' 694 | }, 695 | }, 696 | yaxis: { 697 | title: 'New ' + this.selectedData + ' (in the Past Week)', 698 | type: this.selectedScale == 'Logarithmic Scale' ? 'log' : 'linear', 699 | range: this.selectedScale == 'Logarithmic Scale' ? this.logyrange : this.linearyrange, 700 | titlefont: { 701 | size: 24, 702 | color: 'rgba(254, 52, 110,1)' 703 | }, 704 | }, 705 | hovermode: 'closest', 706 | font: { 707 | family: 'Open Sans, sans-serif', 708 | color: 'black', 709 | size: 14 710 | }, 711 | annotations: this.annotations 712 | }; 713 | }, 714 | 715 | traces() { 716 | 717 | let showDailyMarkers = this.filteredCovidData.length <= 2; 718 | 719 | // draws grey lines (line plot for each location) 720 | let trace1 = this.filteredCovidData.map((e, i) => ({ 721 | x: e.cases.slice(0, this.day), 722 | y: e.slope.slice(0, this.day), 723 | name: e.country, 724 | text: this.dates.map(date => e.country + '
' + this.formatDate(date)), 725 | mode: showDailyMarkers ? 'lines+markers' : 'lines', 726 | type: 'scatter', 727 | legendgroup: i, 728 | marker: { 729 | size: 4, 730 | color: 'rgba(0,0,0,0.15)' 731 | }, 732 | line: { 733 | color: 'rgba(0,0,0,0.15)' 734 | }, 735 | hoverinfo: 'x+y+text', 736 | hovertemplate: '%{text}
Total ' + this.selectedData + ': %{x:,}
Weekly ' + this.selectedData + ': %{y:,}', 737 | }) 738 | ); 739 | 740 | // draws red dots (most recent data for each location) 741 | let trace2 = this.filteredCovidData.map((e, i) => ({ 742 | x: [e.cases[this.day - 1]], 743 | y: [e.slope[this.day - 1]], 744 | text: e.country, 745 | name: e.country, 746 | mode: this.showLabels ? 'markers+text' : 'markers', 747 | legendgroup: i, 748 | textposition: 'center right', 749 | marker: { 750 | size: 6, 751 | color: 'rgba(254, 52, 110, 1)' 752 | }, 753 | hovertemplate: '%{data.text}
Total ' + this.selectedData + ': %{x:,}
Weekly ' + this.selectedData + ': %{y:,}', 754 | 755 | })); 756 | 757 | if (this.showTrendLine && this.doublingTime > 0) { 758 | let cases = [1, 10000000]; 759 | 760 | let trace3 = [{ 761 | x: cases, 762 | y: cases.map(this.referenceLine), 763 | mode: 'lines', 764 | line: { 765 | dash: 'dot', 766 | }, 767 | marker: { 768 | color: 'rgba(114, 27, 101, 0.7)' 769 | }, 770 | hoverinfo: 'skip', 771 | }]; 772 | 773 | // reference line must be last trace for annotation angle to work out 774 | return [...trace1, ...trace2, ...trace3]; 775 | 776 | } else { 777 | return [...trace1, ...trace2]; 778 | } 779 | 780 | }, 781 | 782 | config() { 783 | return { 784 | responsive: true, 785 | toImageButtonOptions: { 786 | format: 'png', // one of png, svg, jpeg, webp 787 | filename: 'Covid Trends', 788 | height: 600, 789 | width: 600 * this.graphAttributes.width / this.graphAttributes.height, 790 | scale: 1 // Multiply title/legend/axis/canvas sizes by this factor 791 | } 792 | }; 793 | }, 794 | 795 | graphData() { 796 | return { 797 | uistate: { // graph is updated when uistate changes 798 | selectedData: this.selectedData, 799 | selectedRegion: this.selectedRegion, 800 | selectedScale: this.selectedScale, 801 | showLabels: this.showLabels, 802 | showTrendLine: this.showTrendLine, 803 | doublingTime: this.doublingTime, 804 | }, 805 | traces: this.traces, 806 | layout: this.layout, 807 | config: this.config 808 | }; 809 | }, 810 | 811 | xmax() { 812 | return Math.max(...this.filteredCases, 50); 813 | }, 814 | 815 | xmin() { 816 | return Math.min(...this.filteredCases, 50); 817 | }, 818 | 819 | ymax() { 820 | return Math.max(...this.filteredSlope, 50); 821 | }, 822 | 823 | ymin() { 824 | return Math.min(...this.filteredSlope); 825 | }, 826 | 827 | filteredCases() { 828 | return Array.prototype.concat(...this.filteredCovidData.map(e => e.cases)).filter(e => !isNaN(e)); 829 | }, 830 | 831 | filteredSlope() { 832 | return Array.prototype.concat(...this.filteredCovidData.map(e => e.slope)).filter(e => !isNaN(e)); 833 | }, 834 | 835 | logxrange() { 836 | return [1, Math.ceil(Math.log10(1.5 * this.xmax))]; 837 | }, 838 | 839 | linearxrange() { 840 | return [-0.49 * Math.pow(10, Math.floor(Math.log10(this.xmax))), Math.round(1.2 * this.xmax)]; 841 | }, 842 | 843 | logyrange() { 844 | 845 | if (this.ymin < 10) { // shift ymin on log scale if fewer than 10 cases 846 | return [0, Math.ceil(Math.log10(1.5 * this.ymax))]; 847 | } else { 848 | return [1, Math.ceil(Math.log10(1.5 * this.ymax))]; 849 | } 850 | }, 851 | 852 | linearyrange() { 853 | let ymax = Math.max(...this.filteredSlope, 50); 854 | return [-Math.pow(10, Math.floor(Math.log10(ymax)) - 2), Math.round(1.05 * ymax)]; 855 | }, 856 | 857 | xAnnotation() { 858 | 859 | if (this.selectedScale == 'Logarithmic Scale') { 860 | let x = this.logyrange[1] - Math.log10(this.referenceLine(1)); 861 | if (x < this.logxrange[1]) { 862 | return x; 863 | } else { 864 | return this.logxrange[1]; 865 | } 866 | 867 | } else { 868 | let x = this.linearyrange[1] / this.referenceLine(1); 869 | if (x < this.linearxrange[1]) { 870 | return x; 871 | } else { 872 | return this.linearxrange[1]; 873 | } 874 | } 875 | }, 876 | 877 | yAnnotation() { 878 | if (this.selectedScale == 'Logarithmic Scale') { 879 | let x = this.logyrange[1] - Math.log10(this.referenceLine(1)); 880 | if (x < this.logxrange[1]) { 881 | return this.logyrange[1]; 882 | } else { 883 | return this.logxrange[1] + Math.log10(this.referenceLine(1)); 884 | } 885 | } else { 886 | let x = this.linearyrange[1] / this.referenceLine(1); 887 | if (x < this.linearxrange[1]) { 888 | return this.linearyrange[1]; 889 | } else { 890 | return this.linearxrange[1] * this.referenceLine(1); 891 | } 892 | } 893 | 894 | } 895 | 896 | }, 897 | 898 | data: { 899 | 900 | paused: true, 901 | 902 | dataTypes: ['Confirmed Cases', 'Reported Deaths'], 903 | 904 | selectedData: 'Confirmed Cases', 905 | 906 | regions: ['World', 'US', 'China', 'Australia', 'Canada'], 907 | 908 | selectedRegion: 'World', 909 | 910 | sliderSelected: false, 911 | 912 | day: 7, 913 | 914 | lookbackTime: 7, 915 | 916 | scale: ['Logarithmic Scale', 'Linear Scale'], 917 | 918 | selectedScale: 'Logarithmic Scale', 919 | 920 | minCasesInCountry: 50, 921 | 922 | dates: [], 923 | 924 | covidData: [], 925 | 926 | countries: [], 927 | 928 | visibleCountries: [], // used for search 929 | 930 | selectedCountries: [], // used to manually select countries 931 | 932 | defaultCountries: [], // used for createURL default check 933 | 934 | isHidden: true, 935 | 936 | showLabels: true, 937 | 938 | showTrendLine: true, 939 | 940 | doublingTime: 2, 941 | 942 | mySelect: '', 943 | 944 | searchField: '', 945 | 946 | autoplay: true, 947 | 948 | firstLoad: true, 949 | 950 | graphAttributes: { 951 | mounted: false, 952 | innerWidth: NaN, 953 | innerHeight: NaN, 954 | width: NaN, 955 | height: NaN, 956 | referenceLineAngle: NaN 957 | }, 958 | 959 | } 960 | 961 | }); 962 | -------------------------------------------------------------------------------- /libraries/vue.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Vue.js v2.6.11 3 | * (c) 2014-2019 Evan You 4 | * Released under the MIT License. 5 | */ 6 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).Vue=t()}(this,function(){"use strict";var e=Object.freeze({});function t(e){return null==e}function n(e){return null!=e}function r(e){return!0===e}function i(e){return"string"==typeof e||"number"==typeof e||"symbol"==typeof e||"boolean"==typeof e}function o(e){return null!==e&&"object"==typeof e}var a=Object.prototype.toString;function s(e){return"[object Object]"===a.call(e)}function c(e){var t=parseFloat(String(e));return t>=0&&Math.floor(t)===t&&isFinite(e)}function u(e){return n(e)&&"function"==typeof e.then&&"function"==typeof e.catch}function l(e){return null==e?"":Array.isArray(e)||s(e)&&e.toString===a?JSON.stringify(e,null,2):String(e)}function f(e){var t=parseFloat(e);return isNaN(t)?e:t}function p(e,t){for(var n=Object.create(null),r=e.split(","),i=0;i-1)return e.splice(n,1)}}var m=Object.prototype.hasOwnProperty;function y(e,t){return m.call(e,t)}function g(e){var t=Object.create(null);return function(n){return t[n]||(t[n]=e(n))}}var _=/-(\w)/g,b=g(function(e){return e.replace(_,function(e,t){return t?t.toUpperCase():""})}),$=g(function(e){return e.charAt(0).toUpperCase()+e.slice(1)}),w=/\B([A-Z])/g,C=g(function(e){return e.replace(w,"-$1").toLowerCase()});var x=Function.prototype.bind?function(e,t){return e.bind(t)}:function(e,t){function n(n){var r=arguments.length;return r?r>1?e.apply(t,arguments):e.call(t,n):e.call(t)}return n._length=e.length,n};function k(e,t){t=t||0;for(var n=e.length-t,r=new Array(n);n--;)r[n]=e[n+t];return r}function A(e,t){for(var n in t)e[n]=t[n];return e}function O(e){for(var t={},n=0;n0,Z=J&&J.indexOf("edge/")>0,G=(J&&J.indexOf("android"),J&&/iphone|ipad|ipod|ios/.test(J)||"ios"===K),X=(J&&/chrome\/\d+/.test(J),J&&/phantomjs/.test(J),J&&J.match(/firefox\/(\d+)/)),Y={}.watch,Q=!1;if(z)try{var ee={};Object.defineProperty(ee,"passive",{get:function(){Q=!0}}),window.addEventListener("test-passive",null,ee)}catch(e){}var te=function(){return void 0===B&&(B=!z&&!V&&"undefined"!=typeof global&&(global.process&&"server"===global.process.env.VUE_ENV)),B},ne=z&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__;function re(e){return"function"==typeof e&&/native code/.test(e.toString())}var ie,oe="undefined"!=typeof Symbol&&re(Symbol)&&"undefined"!=typeof Reflect&&re(Reflect.ownKeys);ie="undefined"!=typeof Set&&re(Set)?Set:function(){function e(){this.set=Object.create(null)}return e.prototype.has=function(e){return!0===this.set[e]},e.prototype.add=function(e){this.set[e]=!0},e.prototype.clear=function(){this.set=Object.create(null)},e}();var ae=S,se=0,ce=function(){this.id=se++,this.subs=[]};ce.prototype.addSub=function(e){this.subs.push(e)},ce.prototype.removeSub=function(e){h(this.subs,e)},ce.prototype.depend=function(){ce.target&&ce.target.addDep(this)},ce.prototype.notify=function(){for(var e=this.subs.slice(),t=0,n=e.length;t-1)if(o&&!y(i,"default"))a=!1;else if(""===a||a===C(e)){var c=Pe(String,i.type);(c<0||s0&&(st((u=e(u,(a||"")+"_"+c))[0])&&st(f)&&(s[l]=he(f.text+u[0].text),u.shift()),s.push.apply(s,u)):i(u)?st(f)?s[l]=he(f.text+u):""!==u&&s.push(he(u)):st(u)&&st(f)?s[l]=he(f.text+u.text):(r(o._isVList)&&n(u.tag)&&t(u.key)&&n(a)&&(u.key="__vlist"+a+"_"+c+"__"),s.push(u)));return s}(e):void 0}function st(e){return n(e)&&n(e.text)&&!1===e.isComment}function ct(e,t){if(e){for(var n=Object.create(null),r=oe?Reflect.ownKeys(e):Object.keys(e),i=0;i0,a=t?!!t.$stable:!o,s=t&&t.$key;if(t){if(t._normalized)return t._normalized;if(a&&r&&r!==e&&s===r.$key&&!o&&!r.$hasNormal)return r;for(var c in i={},t)t[c]&&"$"!==c[0]&&(i[c]=pt(n,c,t[c]))}else i={};for(var u in n)u in i||(i[u]=dt(n,u));return t&&Object.isExtensible(t)&&(t._normalized=i),R(i,"$stable",a),R(i,"$key",s),R(i,"$hasNormal",o),i}function pt(e,t,n){var r=function(){var e=arguments.length?n.apply(null,arguments):n({});return(e=e&&"object"==typeof e&&!Array.isArray(e)?[e]:at(e))&&(0===e.length||1===e.length&&e[0].isComment)?void 0:e};return n.proxy&&Object.defineProperty(e,t,{get:r,enumerable:!0,configurable:!0}),r}function dt(e,t){return function(){return e[t]}}function vt(e,t){var r,i,a,s,c;if(Array.isArray(e)||"string"==typeof e)for(r=new Array(e.length),i=0,a=e.length;idocument.createEvent("Event").timeStamp&&(sn=function(){return cn.now()})}function un(){var e,t;for(an=sn(),rn=!0,Qt.sort(function(e,t){return e.id-t.id}),on=0;onon&&Qt[n].id>e.id;)n--;Qt.splice(n+1,0,e)}else Qt.push(e);nn||(nn=!0,Ye(un))}}(this)},fn.prototype.run=function(){if(this.active){var e=this.get();if(e!==this.value||o(e)||this.deep){var t=this.value;if(this.value=e,this.user)try{this.cb.call(this.vm,e,t)}catch(e){Re(e,this.vm,'callback for watcher "'+this.expression+'"')}else this.cb.call(this.vm,e,t)}}},fn.prototype.evaluate=function(){this.value=this.get(),this.dirty=!1},fn.prototype.depend=function(){for(var e=this.deps.length;e--;)this.deps[e].depend()},fn.prototype.teardown=function(){if(this.active){this.vm._isBeingDestroyed||h(this.vm._watchers,this);for(var e=this.deps.length;e--;)this.deps[e].removeSub(this);this.active=!1}};var pn={enumerable:!0,configurable:!0,get:S,set:S};function dn(e,t,n){pn.get=function(){return this[t][n]},pn.set=function(e){this[t][n]=e},Object.defineProperty(e,n,pn)}function vn(e){e._watchers=[];var t=e.$options;t.props&&function(e,t){var n=e.$options.propsData||{},r=e._props={},i=e.$options._propKeys=[];e.$parent&&$e(!1);var o=function(o){i.push(o);var a=Me(o,t,n,e);xe(r,o,a),o in e||dn(e,"_props",o)};for(var a in t)o(a);$e(!0)}(e,t.props),t.methods&&function(e,t){e.$options.props;for(var n in t)e[n]="function"!=typeof t[n]?S:x(t[n],e)}(e,t.methods),t.data?function(e){var t=e.$options.data;s(t=e._data="function"==typeof t?function(e,t){le();try{return e.call(t,t)}catch(e){return Re(e,t,"data()"),{}}finally{fe()}}(t,e):t||{})||(t={});var n=Object.keys(t),r=e.$options.props,i=(e.$options.methods,n.length);for(;i--;){var o=n[i];r&&y(r,o)||(a=void 0,36!==(a=(o+"").charCodeAt(0))&&95!==a&&dn(e,"_data",o))}var a;Ce(t,!0)}(e):Ce(e._data={},!0),t.computed&&function(e,t){var n=e._computedWatchers=Object.create(null),r=te();for(var i in t){var o=t[i],a="function"==typeof o?o:o.get;r||(n[i]=new fn(e,a||S,S,hn)),i in e||mn(e,i,o)}}(e,t.computed),t.watch&&t.watch!==Y&&function(e,t){for(var n in t){var r=t[n];if(Array.isArray(r))for(var i=0;i-1:"string"==typeof e?e.split(",").indexOf(t)>-1:(n=e,"[object RegExp]"===a.call(n)&&e.test(t));var n}function An(e,t){var n=e.cache,r=e.keys,i=e._vnode;for(var o in n){var a=n[o];if(a){var s=xn(a.componentOptions);s&&!t(s)&&On(n,o,r,i)}}}function On(e,t,n,r){var i=e[t];!i||r&&i.tag===r.tag||i.componentInstance.$destroy(),e[t]=null,h(n,t)}!function(t){t.prototype._init=function(t){var n=this;n._uid=bn++,n._isVue=!0,t&&t._isComponent?function(e,t){var n=e.$options=Object.create(e.constructor.options),r=t._parentVnode;n.parent=t.parent,n._parentVnode=r;var i=r.componentOptions;n.propsData=i.propsData,n._parentListeners=i.listeners,n._renderChildren=i.children,n._componentTag=i.tag,t.render&&(n.render=t.render,n.staticRenderFns=t.staticRenderFns)}(n,t):n.$options=De($n(n.constructor),t||{},n),n._renderProxy=n,n._self=n,function(e){var t=e.$options,n=t.parent;if(n&&!t.abstract){for(;n.$options.abstract&&n.$parent;)n=n.$parent;n.$children.push(e)}e.$parent=n,e.$root=n?n.$root:e,e.$children=[],e.$refs={},e._watcher=null,e._inactive=null,e._directInactive=!1,e._isMounted=!1,e._isDestroyed=!1,e._isBeingDestroyed=!1}(n),function(e){e._events=Object.create(null),e._hasHookEvent=!1;var t=e.$options._parentListeners;t&&qt(e,t)}(n),function(t){t._vnode=null,t._staticTrees=null;var n=t.$options,r=t.$vnode=n._parentVnode,i=r&&r.context;t.$slots=ut(n._renderChildren,i),t.$scopedSlots=e,t._c=function(e,n,r,i){return Pt(t,e,n,r,i,!1)},t.$createElement=function(e,n,r,i){return Pt(t,e,n,r,i,!0)};var o=r&&r.data;xe(t,"$attrs",o&&o.attrs||e,null,!0),xe(t,"$listeners",n._parentListeners||e,null,!0)}(n),Yt(n,"beforeCreate"),function(e){var t=ct(e.$options.inject,e);t&&($e(!1),Object.keys(t).forEach(function(n){xe(e,n,t[n])}),$e(!0))}(n),vn(n),function(e){var t=e.$options.provide;t&&(e._provided="function"==typeof t?t.call(e):t)}(n),Yt(n,"created"),n.$options.el&&n.$mount(n.$options.el)}}(wn),function(e){var t={get:function(){return this._data}},n={get:function(){return this._props}};Object.defineProperty(e.prototype,"$data",t),Object.defineProperty(e.prototype,"$props",n),e.prototype.$set=ke,e.prototype.$delete=Ae,e.prototype.$watch=function(e,t,n){if(s(t))return _n(this,e,t,n);(n=n||{}).user=!0;var r=new fn(this,e,t,n);if(n.immediate)try{t.call(this,r.value)}catch(e){Re(e,this,'callback for immediate watcher "'+r.expression+'"')}return function(){r.teardown()}}}(wn),function(e){var t=/^hook:/;e.prototype.$on=function(e,n){var r=this;if(Array.isArray(e))for(var i=0,o=e.length;i1?k(t):t;for(var n=k(arguments,1),r='event handler for "'+e+'"',i=0,o=t.length;iparseInt(this.max)&&On(a,s[0],s,this._vnode)),t.data.keepAlive=!0}return t||e&&e[0]}}};!function(e){var t={get:function(){return F}};Object.defineProperty(e,"config",t),e.util={warn:ae,extend:A,mergeOptions:De,defineReactive:xe},e.set=ke,e.delete=Ae,e.nextTick=Ye,e.observable=function(e){return Ce(e),e},e.options=Object.create(null),M.forEach(function(t){e.options[t+"s"]=Object.create(null)}),e.options._base=e,A(e.options.components,Tn),function(e){e.use=function(e){var t=this._installedPlugins||(this._installedPlugins=[]);if(t.indexOf(e)>-1)return this;var n=k(arguments,1);return n.unshift(this),"function"==typeof e.install?e.install.apply(e,n):"function"==typeof e&&e.apply(null,n),t.push(e),this}}(e),function(e){e.mixin=function(e){return this.options=De(this.options,e),this}}(e),Cn(e),function(e){M.forEach(function(t){e[t]=function(e,n){return n?("component"===t&&s(n)&&(n.name=n.name||e,n=this.options._base.extend(n)),"directive"===t&&"function"==typeof n&&(n={bind:n,update:n}),this.options[t+"s"][e]=n,n):this.options[t+"s"][e]}})}(e)}(wn),Object.defineProperty(wn.prototype,"$isServer",{get:te}),Object.defineProperty(wn.prototype,"$ssrContext",{get:function(){return this.$vnode&&this.$vnode.ssrContext}}),Object.defineProperty(wn,"FunctionalRenderContext",{value:Tt}),wn.version="2.6.11";var En=p("style,class"),Nn=p("input,textarea,option,select,progress"),jn=function(e,t,n){return"value"===n&&Nn(e)&&"button"!==t||"selected"===n&&"option"===e||"checked"===n&&"input"===e||"muted"===n&&"video"===e},Dn=p("contenteditable,draggable,spellcheck"),Ln=p("events,caret,typing,plaintext-only"),Mn=function(e,t){return Hn(t)||"false"===t?"false":"contenteditable"===e&&Ln(t)?t:"true"},In=p("allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,default,defaultchecked,defaultmuted,defaultselected,defer,disabled,enabled,formnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,muted,nohref,noresize,noshade,novalidate,nowrap,open,pauseonexit,readonly,required,reversed,scoped,seamless,selected,sortable,translate,truespeed,typemustmatch,visible"),Fn="http://www.w3.org/1999/xlink",Pn=function(e){return":"===e.charAt(5)&&"xlink"===e.slice(0,5)},Rn=function(e){return Pn(e)?e.slice(6,e.length):""},Hn=function(e){return null==e||!1===e};function Bn(e){for(var t=e.data,r=e,i=e;n(i.componentInstance);)(i=i.componentInstance._vnode)&&i.data&&(t=Un(i.data,t));for(;n(r=r.parent);)r&&r.data&&(t=Un(t,r.data));return function(e,t){if(n(e)||n(t))return zn(e,Vn(t));return""}(t.staticClass,t.class)}function Un(e,t){return{staticClass:zn(e.staticClass,t.staticClass),class:n(e.class)?[e.class,t.class]:t.class}}function zn(e,t){return e?t?e+" "+t:e:t||""}function Vn(e){return Array.isArray(e)?function(e){for(var t,r="",i=0,o=e.length;i-1?hr(e,t,n):In(t)?Hn(n)?e.removeAttribute(t):(n="allowfullscreen"===t&&"EMBED"===e.tagName?"true":t,e.setAttribute(t,n)):Dn(t)?e.setAttribute(t,Mn(t,n)):Pn(t)?Hn(n)?e.removeAttributeNS(Fn,Rn(t)):e.setAttributeNS(Fn,t,n):hr(e,t,n)}function hr(e,t,n){if(Hn(n))e.removeAttribute(t);else{if(q&&!W&&"TEXTAREA"===e.tagName&&"placeholder"===t&&""!==n&&!e.__ieph){var r=function(t){t.stopImmediatePropagation(),e.removeEventListener("input",r)};e.addEventListener("input",r),e.__ieph=!0}e.setAttribute(t,n)}}var mr={create:dr,update:dr};function yr(e,r){var i=r.elm,o=r.data,a=e.data;if(!(t(o.staticClass)&&t(o.class)&&(t(a)||t(a.staticClass)&&t(a.class)))){var s=Bn(r),c=i._transitionClasses;n(c)&&(s=zn(s,Vn(c))),s!==i._prevClass&&(i.setAttribute("class",s),i._prevClass=s)}}var gr,_r,br,$r,wr,Cr,xr={create:yr,update:yr},kr=/[\w).+\-_$\]]/;function Ar(e){var t,n,r,i,o,a=!1,s=!1,c=!1,u=!1,l=0,f=0,p=0,d=0;for(r=0;r=0&&" "===(h=e.charAt(v));v--);h&&kr.test(h)||(u=!0)}}else void 0===i?(d=r+1,i=e.slice(0,r).trim()):m();function m(){(o||(o=[])).push(e.slice(d,r).trim()),d=r+1}if(void 0===i?i=e.slice(0,r).trim():0!==d&&m(),o)for(r=0;r-1?{exp:e.slice(0,$r),key:'"'+e.slice($r+1)+'"'}:{exp:e,key:null};_r=e,$r=wr=Cr=0;for(;!zr();)Vr(br=Ur())?Jr(br):91===br&&Kr(br);return{exp:e.slice(0,wr),key:e.slice(wr+1,Cr)}}(e);return null===n.key?e+"="+t:"$set("+n.exp+", "+n.key+", "+t+")"}function Ur(){return _r.charCodeAt(++$r)}function zr(){return $r>=gr}function Vr(e){return 34===e||39===e}function Kr(e){var t=1;for(wr=$r;!zr();)if(Vr(e=Ur()))Jr(e);else if(91===e&&t++,93===e&&t--,0===t){Cr=$r;break}}function Jr(e){for(var t=e;!zr()&&(e=Ur())!==t;);}var qr,Wr="__r",Zr="__c";function Gr(e,t,n){var r=qr;return function i(){null!==t.apply(null,arguments)&&Qr(e,i,n,r)}}var Xr=Ve&&!(X&&Number(X[1])<=53);function Yr(e,t,n,r){if(Xr){var i=an,o=t;t=o._wrapper=function(e){if(e.target===e.currentTarget||e.timeStamp>=i||e.timeStamp<=0||e.target.ownerDocument!==document)return o.apply(this,arguments)}}qr.addEventListener(e,t,Q?{capture:n,passive:r}:n)}function Qr(e,t,n,r){(r||qr).removeEventListener(e,t._wrapper||t,n)}function ei(e,r){if(!t(e.data.on)||!t(r.data.on)){var i=r.data.on||{},o=e.data.on||{};qr=r.elm,function(e){if(n(e[Wr])){var t=q?"change":"input";e[t]=[].concat(e[Wr],e[t]||[]),delete e[Wr]}n(e[Zr])&&(e.change=[].concat(e[Zr],e.change||[]),delete e[Zr])}(i),rt(i,o,Yr,Qr,Gr,r.context),qr=void 0}}var ti,ni={create:ei,update:ei};function ri(e,r){if(!t(e.data.domProps)||!t(r.data.domProps)){var i,o,a=r.elm,s=e.data.domProps||{},c=r.data.domProps||{};for(i in n(c.__ob__)&&(c=r.data.domProps=A({},c)),s)i in c||(a[i]="");for(i in c){if(o=c[i],"textContent"===i||"innerHTML"===i){if(r.children&&(r.children.length=0),o===s[i])continue;1===a.childNodes.length&&a.removeChild(a.childNodes[0])}if("value"===i&&"PROGRESS"!==a.tagName){a._value=o;var u=t(o)?"":String(o);ii(a,u)&&(a.value=u)}else if("innerHTML"===i&&qn(a.tagName)&&t(a.innerHTML)){(ti=ti||document.createElement("div")).innerHTML=""+o+"";for(var l=ti.firstChild;a.firstChild;)a.removeChild(a.firstChild);for(;l.firstChild;)a.appendChild(l.firstChild)}else if(o!==s[i])try{a[i]=o}catch(e){}}}}function ii(e,t){return!e.composing&&("OPTION"===e.tagName||function(e,t){var n=!0;try{n=document.activeElement!==e}catch(e){}return n&&e.value!==t}(e,t)||function(e,t){var r=e.value,i=e._vModifiers;if(n(i)){if(i.number)return f(r)!==f(t);if(i.trim)return r.trim()!==t.trim()}return r!==t}(e,t))}var oi={create:ri,update:ri},ai=g(function(e){var t={},n=/:(.+)/;return e.split(/;(?![^(]*\))/g).forEach(function(e){if(e){var r=e.split(n);r.length>1&&(t[r[0].trim()]=r[1].trim())}}),t});function si(e){var t=ci(e.style);return e.staticStyle?A(e.staticStyle,t):t}function ci(e){return Array.isArray(e)?O(e):"string"==typeof e?ai(e):e}var ui,li=/^--/,fi=/\s*!important$/,pi=function(e,t,n){if(li.test(t))e.style.setProperty(t,n);else if(fi.test(n))e.style.setProperty(C(t),n.replace(fi,""),"important");else{var r=vi(t);if(Array.isArray(n))for(var i=0,o=n.length;i-1?t.split(yi).forEach(function(t){return e.classList.add(t)}):e.classList.add(t);else{var n=" "+(e.getAttribute("class")||"")+" ";n.indexOf(" "+t+" ")<0&&e.setAttribute("class",(n+t).trim())}}function _i(e,t){if(t&&(t=t.trim()))if(e.classList)t.indexOf(" ")>-1?t.split(yi).forEach(function(t){return e.classList.remove(t)}):e.classList.remove(t),e.classList.length||e.removeAttribute("class");else{for(var n=" "+(e.getAttribute("class")||"")+" ",r=" "+t+" ";n.indexOf(r)>=0;)n=n.replace(r," ");(n=n.trim())?e.setAttribute("class",n):e.removeAttribute("class")}}function bi(e){if(e){if("object"==typeof e){var t={};return!1!==e.css&&A(t,$i(e.name||"v")),A(t,e),t}return"string"==typeof e?$i(e):void 0}}var $i=g(function(e){return{enterClass:e+"-enter",enterToClass:e+"-enter-to",enterActiveClass:e+"-enter-active",leaveClass:e+"-leave",leaveToClass:e+"-leave-to",leaveActiveClass:e+"-leave-active"}}),wi=z&&!W,Ci="transition",xi="animation",ki="transition",Ai="transitionend",Oi="animation",Si="animationend";wi&&(void 0===window.ontransitionend&&void 0!==window.onwebkittransitionend&&(ki="WebkitTransition",Ai="webkitTransitionEnd"),void 0===window.onanimationend&&void 0!==window.onwebkitanimationend&&(Oi="WebkitAnimation",Si="webkitAnimationEnd"));var Ti=z?window.requestAnimationFrame?window.requestAnimationFrame.bind(window):setTimeout:function(e){return e()};function Ei(e){Ti(function(){Ti(e)})}function Ni(e,t){var n=e._transitionClasses||(e._transitionClasses=[]);n.indexOf(t)<0&&(n.push(t),gi(e,t))}function ji(e,t){e._transitionClasses&&h(e._transitionClasses,t),_i(e,t)}function Di(e,t,n){var r=Mi(e,t),i=r.type,o=r.timeout,a=r.propCount;if(!i)return n();var s=i===Ci?Ai:Si,c=0,u=function(){e.removeEventListener(s,l),n()},l=function(t){t.target===e&&++c>=a&&u()};setTimeout(function(){c0&&(n=Ci,l=a,f=o.length):t===xi?u>0&&(n=xi,l=u,f=c.length):f=(n=(l=Math.max(a,u))>0?a>u?Ci:xi:null)?n===Ci?o.length:c.length:0,{type:n,timeout:l,propCount:f,hasTransform:n===Ci&&Li.test(r[ki+"Property"])}}function Ii(e,t){for(;e.length1}function Ui(e,t){!0!==t.data.show&&Pi(t)}var zi=function(e){var o,a,s={},c=e.modules,u=e.nodeOps;for(o=0;ov?_(e,t(i[y+1])?null:i[y+1].elm,i,d,y,o):d>y&&$(r,p,v)}(p,h,y,o,l):n(y)?(n(e.text)&&u.setTextContent(p,""),_(p,null,y,0,y.length-1,o)):n(h)?$(h,0,h.length-1):n(e.text)&&u.setTextContent(p,""):e.text!==i.text&&u.setTextContent(p,i.text),n(v)&&n(d=v.hook)&&n(d=d.postpatch)&&d(e,i)}}}function k(e,t,i){if(r(i)&&n(e.parent))e.parent.data.pendingInsert=t;else for(var o=0;o-1,a.selected!==o&&(a.selected=o);else if(N(Wi(a),r))return void(e.selectedIndex!==s&&(e.selectedIndex=s));i||(e.selectedIndex=-1)}}function qi(e,t){return t.every(function(t){return!N(t,e)})}function Wi(e){return"_value"in e?e._value:e.value}function Zi(e){e.target.composing=!0}function Gi(e){e.target.composing&&(e.target.composing=!1,Xi(e.target,"input"))}function Xi(e,t){var n=document.createEvent("HTMLEvents");n.initEvent(t,!0,!0),e.dispatchEvent(n)}function Yi(e){return!e.componentInstance||e.data&&e.data.transition?e:Yi(e.componentInstance._vnode)}var Qi={model:Vi,show:{bind:function(e,t,n){var r=t.value,i=(n=Yi(n)).data&&n.data.transition,o=e.__vOriginalDisplay="none"===e.style.display?"":e.style.display;r&&i?(n.data.show=!0,Pi(n,function(){e.style.display=o})):e.style.display=r?o:"none"},update:function(e,t,n){var r=t.value;!r!=!t.oldValue&&((n=Yi(n)).data&&n.data.transition?(n.data.show=!0,r?Pi(n,function(){e.style.display=e.__vOriginalDisplay}):Ri(n,function(){e.style.display="none"})):e.style.display=r?e.__vOriginalDisplay:"none")},unbind:function(e,t,n,r,i){i||(e.style.display=e.__vOriginalDisplay)}}},eo={name:String,appear:Boolean,css:Boolean,mode:String,type:String,enterClass:String,leaveClass:String,enterToClass:String,leaveToClass:String,enterActiveClass:String,leaveActiveClass:String,appearClass:String,appearActiveClass:String,appearToClass:String,duration:[Number,String,Object]};function to(e){var t=e&&e.componentOptions;return t&&t.Ctor.options.abstract?to(zt(t.children)):e}function no(e){var t={},n=e.$options;for(var r in n.propsData)t[r]=e[r];var i=n._parentListeners;for(var o in i)t[b(o)]=i[o];return t}function ro(e,t){if(/\d-keep-alive$/.test(t.tag))return e("keep-alive",{props:t.componentOptions.propsData})}var io=function(e){return e.tag||Ut(e)},oo=function(e){return"show"===e.name},ao={name:"transition",props:eo,abstract:!0,render:function(e){var t=this,n=this.$slots.default;if(n&&(n=n.filter(io)).length){var r=this.mode,o=n[0];if(function(e){for(;e=e.parent;)if(e.data.transition)return!0}(this.$vnode))return o;var a=to(o);if(!a)return o;if(this._leaving)return ro(e,o);var s="__transition-"+this._uid+"-";a.key=null==a.key?a.isComment?s+"comment":s+a.tag:i(a.key)?0===String(a.key).indexOf(s)?a.key:s+a.key:a.key;var c=(a.data||(a.data={})).transition=no(this),u=this._vnode,l=to(u);if(a.data.directives&&a.data.directives.some(oo)&&(a.data.show=!0),l&&l.data&&!function(e,t){return t.key===e.key&&t.tag===e.tag}(a,l)&&!Ut(l)&&(!l.componentInstance||!l.componentInstance._vnode.isComment)){var f=l.data.transition=A({},c);if("out-in"===r)return this._leaving=!0,it(f,"afterLeave",function(){t._leaving=!1,t.$forceUpdate()}),ro(e,o);if("in-out"===r){if(Ut(a))return u;var p,d=function(){p()};it(c,"afterEnter",d),it(c,"enterCancelled",d),it(f,"delayLeave",function(e){p=e})}}return o}}},so=A({tag:String,moveClass:String},eo);function co(e){e.elm._moveCb&&e.elm._moveCb(),e.elm._enterCb&&e.elm._enterCb()}function uo(e){e.data.newPos=e.elm.getBoundingClientRect()}function lo(e){var t=e.data.pos,n=e.data.newPos,r=t.left-n.left,i=t.top-n.top;if(r||i){e.data.moved=!0;var o=e.elm.style;o.transform=o.WebkitTransform="translate("+r+"px,"+i+"px)",o.transitionDuration="0s"}}delete so.mode;var fo={Transition:ao,TransitionGroup:{props:so,beforeMount:function(){var e=this,t=this._update;this._update=function(n,r){var i=Zt(e);e.__patch__(e._vnode,e.kept,!1,!0),e._vnode=e.kept,i(),t.call(e,n,r)}},render:function(e){for(var t=this.tag||this.$vnode.data.tag||"span",n=Object.create(null),r=this.prevChildren=this.children,i=this.$slots.default||[],o=this.children=[],a=no(this),s=0;s-1?Gn[e]=t.constructor===window.HTMLUnknownElement||t.constructor===window.HTMLElement:Gn[e]=/HTMLUnknownElement/.test(t.toString())},A(wn.options.directives,Qi),A(wn.options.components,fo),wn.prototype.__patch__=z?zi:S,wn.prototype.$mount=function(e,t){return function(e,t,n){var r;return e.$el=t,e.$options.render||(e.$options.render=ve),Yt(e,"beforeMount"),r=function(){e._update(e._render(),n)},new fn(e,r,S,{before:function(){e._isMounted&&!e._isDestroyed&&Yt(e,"beforeUpdate")}},!0),n=!1,null==e.$vnode&&(e._isMounted=!0,Yt(e,"mounted")),e}(this,e=e&&z?Yn(e):void 0,t)},z&&setTimeout(function(){F.devtools&&ne&&ne.emit("init",wn)},0);var po=/\{\{((?:.|\r?\n)+?)\}\}/g,vo=/[-.*+?^${}()|[\]\/\\]/g,ho=g(function(e){var t=e[0].replace(vo,"\\$&"),n=e[1].replace(vo,"\\$&");return new RegExp(t+"((?:.|\\n)+?)"+n,"g")});var mo={staticKeys:["staticClass"],transformNode:function(e,t){t.warn;var n=Fr(e,"class");n&&(e.staticClass=JSON.stringify(n));var r=Ir(e,"class",!1);r&&(e.classBinding=r)},genData:function(e){var t="";return e.staticClass&&(t+="staticClass:"+e.staticClass+","),e.classBinding&&(t+="class:"+e.classBinding+","),t}};var yo,go={staticKeys:["staticStyle"],transformNode:function(e,t){t.warn;var n=Fr(e,"style");n&&(e.staticStyle=JSON.stringify(ai(n)));var r=Ir(e,"style",!1);r&&(e.styleBinding=r)},genData:function(e){var t="";return e.staticStyle&&(t+="staticStyle:"+e.staticStyle+","),e.styleBinding&&(t+="style:("+e.styleBinding+"),"),t}},_o=function(e){return(yo=yo||document.createElement("div")).innerHTML=e,yo.textContent},bo=p("area,base,br,col,embed,frame,hr,img,input,isindex,keygen,link,meta,param,source,track,wbr"),$o=p("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source"),wo=p("address,article,aside,base,blockquote,body,caption,col,colgroup,dd,details,dialog,div,dl,dt,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,head,header,hgroup,hr,html,legend,li,menuitem,meta,optgroup,option,param,rp,rt,source,style,summary,tbody,td,tfoot,th,thead,title,tr,track"),Co=/^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/,xo=/^\s*((?:v-[\w-]+:|@|:|#)\[[^=]+\][^\s"'<>\/=]*)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/,ko="[a-zA-Z_][\\-\\.0-9_a-zA-Z"+P.source+"]*",Ao="((?:"+ko+"\\:)?"+ko+")",Oo=new RegExp("^<"+Ao),So=/^\s*(\/?)>/,To=new RegExp("^<\\/"+Ao+"[^>]*>"),Eo=/^]+>/i,No=/^",""":'"',"&":"&"," ":"\n"," ":"\t","'":"'"},Io=/&(?:lt|gt|quot|amp|#39);/g,Fo=/&(?:lt|gt|quot|amp|#39|#10|#9);/g,Po=p("pre,textarea",!0),Ro=function(e,t){return e&&Po(e)&&"\n"===t[0]};function Ho(e,t){var n=t?Fo:Io;return e.replace(n,function(e){return Mo[e]})}var Bo,Uo,zo,Vo,Ko,Jo,qo,Wo,Zo=/^@|^v-on:/,Go=/^v-|^@|^:|^#/,Xo=/([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/,Yo=/,([^,\}\]]*)(?:,([^,\}\]]*))?$/,Qo=/^\(|\)$/g,ea=/^\[.*\]$/,ta=/:(.*)$/,na=/^:|^\.|^v-bind:/,ra=/\.[^.\]]+(?=[^\]]*$)/g,ia=/^v-slot(:|$)|^#/,oa=/[\r\n]/,aa=/\s+/g,sa=g(_o),ca="_empty_";function ua(e,t,n){return{type:1,tag:e,attrsList:t,attrsMap:ma(t),rawAttrsMap:{},parent:n,children:[]}}function la(e,t){Bo=t.warn||Sr,Jo=t.isPreTag||T,qo=t.mustUseProp||T,Wo=t.getTagNamespace||T;t.isReservedTag;zo=Tr(t.modules,"transformNode"),Vo=Tr(t.modules,"preTransformNode"),Ko=Tr(t.modules,"postTransformNode"),Uo=t.delimiters;var n,r,i=[],o=!1!==t.preserveWhitespace,a=t.whitespace,s=!1,c=!1;function u(e){if(l(e),s||e.processed||(e=fa(e,t)),i.length||e===n||n.if&&(e.elseif||e.else)&&da(n,{exp:e.elseif,block:e}),r&&!e.forbidden)if(e.elseif||e.else)a=e,(u=function(e){var t=e.length;for(;t--;){if(1===e[t].type)return e[t];e.pop()}}(r.children))&&u.if&&da(u,{exp:a.elseif,block:a});else{if(e.slotScope){var o=e.slotTarget||'"default"';(r.scopedSlots||(r.scopedSlots={}))[o]=e}r.children.push(e),e.parent=r}var a,u;e.children=e.children.filter(function(e){return!e.slotScope}),l(e),e.pre&&(s=!1),Jo(e.tag)&&(c=!1);for(var f=0;f]*>)","i")),p=e.replace(f,function(e,n,r){return u=r.length,Do(l)||"noscript"===l||(n=n.replace(//g,"$1").replace(//g,"$1")),Ro(l,n)&&(n=n.slice(1)),t.chars&&t.chars(n),""});c+=e.length-p.length,e=p,A(l,c-u,c)}else{var d=e.indexOf("<");if(0===d){if(No.test(e)){var v=e.indexOf("--\x3e");if(v>=0){t.shouldKeepComment&&t.comment(e.substring(4,v),c,c+v+3),C(v+3);continue}}if(jo.test(e)){var h=e.indexOf("]>");if(h>=0){C(h+2);continue}}var m=e.match(Eo);if(m){C(m[0].length);continue}var y=e.match(To);if(y){var g=c;C(y[0].length),A(y[1],g,c);continue}var _=x();if(_){k(_),Ro(_.tagName,e)&&C(1);continue}}var b=void 0,$=void 0,w=void 0;if(d>=0){for($=e.slice(d);!(To.test($)||Oo.test($)||No.test($)||jo.test($)||(w=$.indexOf("<",1))<0);)d+=w,$=e.slice(d);b=e.substring(0,d)}d<0&&(b=e),b&&C(b.length),t.chars&&b&&t.chars(b,c-b.length,c)}if(e===n){t.chars&&t.chars(e);break}}function C(t){c+=t,e=e.substring(t)}function x(){var t=e.match(Oo);if(t){var n,r,i={tagName:t[1],attrs:[],start:c};for(C(t[0].length);!(n=e.match(So))&&(r=e.match(xo)||e.match(Co));)r.start=c,C(r[0].length),r.end=c,i.attrs.push(r);if(n)return i.unarySlash=n[1],C(n[0].length),i.end=c,i}}function k(e){var n=e.tagName,c=e.unarySlash;o&&("p"===r&&wo(n)&&A(r),s(n)&&r===n&&A(n));for(var u=a(n)||!!c,l=e.attrs.length,f=new Array(l),p=0;p=0&&i[a].lowerCasedTag!==s;a--);else a=0;if(a>=0){for(var u=i.length-1;u>=a;u--)t.end&&t.end(i[u].tag,n,o);i.length=a,r=a&&i[a-1].tag}else"br"===s?t.start&&t.start(e,[],!0,n,o):"p"===s&&(t.start&&t.start(e,[],!1,n,o),t.end&&t.end(e,n,o))}A()}(e,{warn:Bo,expectHTML:t.expectHTML,isUnaryTag:t.isUnaryTag,canBeLeftOpenTag:t.canBeLeftOpenTag,shouldDecodeNewlines:t.shouldDecodeNewlines,shouldDecodeNewlinesForHref:t.shouldDecodeNewlinesForHref,shouldKeepComment:t.comments,outputSourceRange:t.outputSourceRange,start:function(e,o,a,l,f){var p=r&&r.ns||Wo(e);q&&"svg"===p&&(o=function(e){for(var t=[],n=0;nc&&(s.push(o=e.slice(c,i)),a.push(JSON.stringify(o)));var u=Ar(r[1].trim());a.push("_s("+u+")"),s.push({"@binding":u}),c=i+r[0].length}return c-1"+("true"===o?":("+t+")":":_q("+t+","+o+")")),Mr(e,"change","var $$a="+t+",$$el=$event.target,$$c=$$el.checked?("+o+"):("+a+");if(Array.isArray($$a)){var $$v="+(r?"_n("+i+")":i)+",$$i=_i($$a,$$v);if($$el.checked){$$i<0&&("+Br(t,"$$a.concat([$$v])")+")}else{$$i>-1&&("+Br(t,"$$a.slice(0,$$i).concat($$a.slice($$i+1))")+")}}else{"+Br(t,"$$c")+"}",null,!0)}(e,r,i);else if("input"===o&&"radio"===a)!function(e,t,n){var r=n&&n.number,i=Ir(e,"value")||"null";Er(e,"checked","_q("+t+","+(i=r?"_n("+i+")":i)+")"),Mr(e,"change",Br(t,i),null,!0)}(e,r,i);else if("input"===o||"textarea"===o)!function(e,t,n){var r=e.attrsMap.type,i=n||{},o=i.lazy,a=i.number,s=i.trim,c=!o&&"range"!==r,u=o?"change":"range"===r?Wr:"input",l="$event.target.value";s&&(l="$event.target.value.trim()"),a&&(l="_n("+l+")");var f=Br(t,l);c&&(f="if($event.target.composing)return;"+f),Er(e,"value","("+t+")"),Mr(e,u,f,null,!0),(s||a)&&Mr(e,"blur","$forceUpdate()")}(e,r,i);else if(!F.isReservedTag(o))return Hr(e,r,i),!1;return!0},text:function(e,t){t.value&&Er(e,"textContent","_s("+t.value+")",t)},html:function(e,t){t.value&&Er(e,"innerHTML","_s("+t.value+")",t)}},isPreTag:function(e){return"pre"===e},isUnaryTag:bo,mustUseProp:jn,canBeLeftOpenTag:$o,isReservedTag:Wn,getTagNamespace:Zn,staticKeys:function(e){return e.reduce(function(e,t){return e.concat(t.staticKeys||[])},[]).join(",")}(ba)},xa=g(function(e){return p("type,tag,attrsList,attrsMap,plain,parent,children,attrs,start,end,rawAttrsMap"+(e?","+e:""))});function ka(e,t){e&&($a=xa(t.staticKeys||""),wa=t.isReservedTag||T,function e(t){t.static=function(e){if(2===e.type)return!1;if(3===e.type)return!0;return!(!e.pre&&(e.hasBindings||e.if||e.for||d(e.tag)||!wa(e.tag)||function(e){for(;e.parent;){if("template"!==(e=e.parent).tag)return!1;if(e.for)return!0}return!1}(e)||!Object.keys(e).every($a)))}(t);if(1===t.type){if(!wa(t.tag)&&"slot"!==t.tag&&null==t.attrsMap["inline-template"])return;for(var n=0,r=t.children.length;n|^function(?:\s+[\w$]+)?\s*\(/,Oa=/\([^)]*?\);*$/,Sa=/^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['[^']*?']|\["[^"]*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*$/,Ta={esc:27,tab:9,enter:13,space:32,up:38,left:37,right:39,down:40,delete:[8,46]},Ea={esc:["Esc","Escape"],tab:"Tab",enter:"Enter",space:[" ","Spacebar"],up:["Up","ArrowUp"],left:["Left","ArrowLeft"],right:["Right","ArrowRight"],down:["Down","ArrowDown"],delete:["Backspace","Delete","Del"]},Na=function(e){return"if("+e+")return null;"},ja={stop:"$event.stopPropagation();",prevent:"$event.preventDefault();",self:Na("$event.target !== $event.currentTarget"),ctrl:Na("!$event.ctrlKey"),shift:Na("!$event.shiftKey"),alt:Na("!$event.altKey"),meta:Na("!$event.metaKey"),left:Na("'button' in $event && $event.button !== 0"),middle:Na("'button' in $event && $event.button !== 1"),right:Na("'button' in $event && $event.button !== 2")};function Da(e,t){var n=t?"nativeOn:":"on:",r="",i="";for(var o in e){var a=La(e[o]);e[o]&&e[o].dynamic?i+=o+","+a+",":r+='"'+o+'":'+a+","}return r="{"+r.slice(0,-1)+"}",i?n+"_d("+r+",["+i.slice(0,-1)+"])":n+r}function La(e){if(!e)return"function(){}";if(Array.isArray(e))return"["+e.map(function(e){return La(e)}).join(",")+"]";var t=Sa.test(e.value),n=Aa.test(e.value),r=Sa.test(e.value.replace(Oa,""));if(e.modifiers){var i="",o="",a=[];for(var s in e.modifiers)if(ja[s])o+=ja[s],Ta[s]&&a.push(s);else if("exact"===s){var c=e.modifiers;o+=Na(["ctrl","shift","alt","meta"].filter(function(e){return!c[e]}).map(function(e){return"$event."+e+"Key"}).join("||"))}else a.push(s);return a.length&&(i+=function(e){return"if(!$event.type.indexOf('key')&&"+e.map(Ma).join("&&")+")return null;"}(a)),o&&(i+=o),"function($event){"+i+(t?"return "+e.value+"($event)":n?"return ("+e.value+")($event)":r?"return "+e.value:e.value)+"}"}return t||n?e.value:"function($event){"+(r?"return "+e.value:e.value)+"}"}function Ma(e){var t=parseInt(e,10);if(t)return"$event.keyCode!=="+t;var n=Ta[e],r=Ea[e];return"_k($event.keyCode,"+JSON.stringify(e)+","+JSON.stringify(n)+",$event.key,"+JSON.stringify(r)+")"}var Ia={on:function(e,t){e.wrapListeners=function(e){return"_g("+e+","+t.value+")"}},bind:function(e,t){e.wrapData=function(n){return"_b("+n+",'"+e.tag+"',"+t.value+","+(t.modifiers&&t.modifiers.prop?"true":"false")+(t.modifiers&&t.modifiers.sync?",true":"")+")"}},cloak:S},Fa=function(e){this.options=e,this.warn=e.warn||Sr,this.transforms=Tr(e.modules,"transformCode"),this.dataGenFns=Tr(e.modules,"genData"),this.directives=A(A({},Ia),e.directives);var t=e.isReservedTag||T;this.maybeComponent=function(e){return!!e.component||!t(e.tag)},this.onceId=0,this.staticRenderFns=[],this.pre=!1};function Pa(e,t){var n=new Fa(t);return{render:"with(this){return "+(e?Ra(e,n):'_c("div")')+"}",staticRenderFns:n.staticRenderFns}}function Ra(e,t){if(e.parent&&(e.pre=e.pre||e.parent.pre),e.staticRoot&&!e.staticProcessed)return Ha(e,t);if(e.once&&!e.onceProcessed)return Ba(e,t);if(e.for&&!e.forProcessed)return za(e,t);if(e.if&&!e.ifProcessed)return Ua(e,t);if("template"!==e.tag||e.slotTarget||t.pre){if("slot"===e.tag)return function(e,t){var n=e.slotName||'"default"',r=qa(e,t),i="_t("+n+(r?","+r:""),o=e.attrs||e.dynamicAttrs?Ga((e.attrs||[]).concat(e.dynamicAttrs||[]).map(function(e){return{name:b(e.name),value:e.value,dynamic:e.dynamic}})):null,a=e.attrsMap["v-bind"];!o&&!a||r||(i+=",null");o&&(i+=","+o);a&&(i+=(o?"":",null")+","+a);return i+")"}(e,t);var n;if(e.component)n=function(e,t,n){var r=t.inlineTemplate?null:qa(t,n,!0);return"_c("+e+","+Va(t,n)+(r?","+r:"")+")"}(e.component,e,t);else{var r;(!e.plain||e.pre&&t.maybeComponent(e))&&(r=Va(e,t));var i=e.inlineTemplate?null:qa(e,t,!0);n="_c('"+e.tag+"'"+(r?","+r:"")+(i?","+i:"")+")"}for(var o=0;o>>0}(a):"")+")"}(e,e.scopedSlots,t)+","),e.model&&(n+="model:{value:"+e.model.value+",callback:"+e.model.callback+",expression:"+e.model.expression+"},"),e.inlineTemplate){var o=function(e,t){var n=e.children[0];if(n&&1===n.type){var r=Pa(n,t.options);return"inlineTemplate:{render:function(){"+r.render+"},staticRenderFns:["+r.staticRenderFns.map(function(e){return"function(){"+e+"}"}).join(",")+"]}"}}(e,t);o&&(n+=o+",")}return n=n.replace(/,$/,"")+"}",e.dynamicAttrs&&(n="_b("+n+',"'+e.tag+'",'+Ga(e.dynamicAttrs)+")"),e.wrapData&&(n=e.wrapData(n)),e.wrapListeners&&(n=e.wrapListeners(n)),n}function Ka(e){return 1===e.type&&("slot"===e.tag||e.children.some(Ka))}function Ja(e,t){var n=e.attrsMap["slot-scope"];if(e.if&&!e.ifProcessed&&!n)return Ua(e,t,Ja,"null");if(e.for&&!e.forProcessed)return za(e,t,Ja);var r=e.slotScope===ca?"":String(e.slotScope),i="function("+r+"){return "+("template"===e.tag?e.if&&n?"("+e.if+")?"+(qa(e,t)||"undefined")+":undefined":qa(e,t)||"undefined":Ra(e,t))+"}",o=r?"":",proxy:true";return"{key:"+(e.slotTarget||'"default"')+",fn:"+i+o+"}"}function qa(e,t,n,r,i){var o=e.children;if(o.length){var a=o[0];if(1===o.length&&a.for&&"template"!==a.tag&&"slot"!==a.tag){var s=n?t.maybeComponent(a)?",1":",0":"";return""+(r||Ra)(a,t)+s}var c=n?function(e,t){for(var n=0,r=0;r':'
',ts.innerHTML.indexOf(" ")>0}var os=!!z&&is(!1),as=!!z&&is(!0),ss=g(function(e){var t=Yn(e);return t&&t.innerHTML}),cs=wn.prototype.$mount;return wn.prototype.$mount=function(e,t){if((e=e&&Yn(e))===document.body||e===document.documentElement)return this;var n=this.$options;if(!n.render){var r=n.template;if(r)if("string"==typeof r)"#"===r.charAt(0)&&(r=ss(r));else{if(!r.nodeType)return this;r=r.innerHTML}else e&&(r=function(e){if(e.outerHTML)return e.outerHTML;var t=document.createElement("div");return t.appendChild(e.cloneNode(!0)),t.innerHTML}(e));if(r){var i=rs(r,{outputSourceRange:!1,shouldDecodeNewlines:os,shouldDecodeNewlinesForHref:as,delimiters:n.delimiters,comments:n.comments},this),o=i.render,a=i.staticRenderFns;n.render=o,n.staticRenderFns=a}}return cs.call(this,e,t)},wn.compile=rs,wn}); --------------------------------------------------------------------------------