From 0cf482ee6e4c28f78f7a674d0c9c33c02f6b2e6d Mon Sep 17 00:00:00 2001 From: miaomiao612 Date: Wed, 9 Nov 2022 08:03:10 +0800 Subject: [PATCH 01/33] change --- site/css/style.css | 0 site/index.html | 0 site/js/index.js | 0 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 site/css/style.css create mode 100644 site/index.html create mode 100644 site/js/index.js diff --git a/site/css/style.css b/site/css/style.css new file mode 100644 index 0000000..e69de29 diff --git a/site/index.html b/site/index.html new file mode 100644 index 0000000..e69de29 diff --git a/site/js/index.js b/site/js/index.js new file mode 100644 index 0000000..e69de29 From d731c4306afd42ac569489110fbac939520aff20 Mon Sep 17 00:00:00 2001 From: Yifei SUN <100406743+miaomiao612@users.noreply.github.com> Date: Thu, 10 Nov 2022 04:28:51 +0800 Subject: [PATCH 02/33] Create README.md --- README.md | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..3dfcc62 --- /dev/null +++ b/README.md @@ -0,0 +1,67 @@ +## Core Interface Elements + +### Layout + +* [ ] Unless otherwise specified, all features should be useable on both small (mobile) and large (laptop/desktop) screens. **Your HTML document should have appropriate `meta` tag(s) to make this possible.** + +### Loading voter files... + +* [ ] There should be an `input` element on the page where you can enter a voter file number. **Save the `input` DOM element in a variable named `voterFileInput` attached to the global `window` object.** In other words: + + ```js + window.voterFileInput = ...; + ``` + +* [ ] There should be a `button` that will load the voter file number given in the `voterFileInput` when clicked. **Save the `button` DOM element in a variable named `voterFileLoadButton` attached to the global `window` object.** + +### Listing and mapping voters... + +* [ ] Your page should have an element that shows the voters (and their addresses) from a file. Note that the element _does not_ need to be a `ul`, `ol`, or any other HTML list element. Even though the element itself may not use a list tag like `ul` or `ol`, it will still function as a list and I'll still refer to it as one. **The list's DOM element should be available on the global `window` object as a variable named `voterList`.** + +* [ ] Your page should have a Leaflet map to show voter locations. **The Leaflet map object should be available on the global `window` object as a variable named `voterMap`.** + +* When you enter a file number, the voter information in that CSV file should be loaded onto the `voterMap` and into the `voterList`. + * [ ] **Wrap each voter's name in an element (for example a `span`) with the class `voter-name`. Wrap addresses in an element with the class `voter-address`** You may choose to list each voter individually or grouped by address, which I would recommend. Either way, each voter's basic information (at least their name and street address) should be shown in the `voterList`. + * [ ] **Represent the voters in the file with map markers.** You may choose to have one map marker to represent each voter, one marker to represent each address, or one marker to represent each _building_ (for example, two apartments that share the same street address are in the same building). I would generally recommend showing a marker for each building, as otherwise markers for different apartments or voters in the same building will be overlapping. + +* [ ] When you click on a map marker, the marker should be highlighted in some way to show that it is selected. **Change the marker styles of a selected marker if it is a vector marker (e.g. `L.circleMarker`), or change the icon if it is a normal image marker (e.g. `L.marker`).** + +* [ ] When you click on a map marker, the corresponding item(s) in the `voterList` should also be highlighted. **Add a class named `selected` to the appropriate element(s) within the `voterList`.** Use that `selected` class to apply different visual styles to the element(s). + +### Displaying and editing voter details... + +> _Note that if you decide to implement a workflow that doesn't precisely fit into the structure below, that's ok! Just talk with me about what the workflow is, because we may need to modify the project tests._ + +* [ ] When you click on a voter (or an address) in the `voterList`, a panel should be shown that contains details about the voter (or about each voter at the address). This panel could be represented in HTML with a `div`, `form`, `section`, or any of a number of other elements. **Give the voter information panel(s) a class of `voter-details`.** + +* [ ] There should be _at least_ three separate input elements available for collecting facts about each voter (refer to the [product requirements document](PRD.md) that we created in class to remind yourself what kind of information should be collected). **Include fields for collecting voter information on each `voter-details` panel.** + +* [ ] There should be a button on the voter details panel that allows a user to save the information entered when it is clicked. **Include such a button and give it a class `voter-details-save-btn`.** + +* [ ] Voter details should be persisted to local memory. **When voter details are closed, the page is reloaded, and the voter information is loaded again, the value in each of the inputs in the `voter-details` panel should be recalled.** + +## Stretch 1: Store Voter Details in the Cloud + +* In addition to saving data locally on a single browser, make it so that voter data will be recalled regardless of the device you're using. + +## Stretch 2: User Feedback + +* Use a toast or some other type of notification method to let the user know that their data has been successfully saved. +* Give the user gamified feedback such as toasts or alerts when they're a certain amount of the way through the voter file. + +## Stretch 3: High-level Voter File Stats + +* Include a view (either on the same HTML page or a different one) where you can display high-level summary charts and info about a voter file, such as: + * the proportion of each political party represented in the file, + * the number/proportion of doors you've already knocked on, or + * the number/proportion of people you've already talked to from the file. + +## Stretch 4: Voting Record + +* Include a voter's voting record information in the voter details, ordered by their participation in elections from most recent to least recent. + +## Stretch 5: Geolocation + +* Show the closest voters that the user hasn't yet visited at the top of the address list. This way the user should always be able to simple look at the next voter/address in the list. + + > Note: this can be done using (1) the [geolocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API), (2) a library like [turf.js](https://turfjs.org/), and (3) JavaScript's [`Array.sort` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) which can admittedly be pretty weird at first. From 4e75c7df19dd52e61cfc6c22e94053879dc1621a Mon Sep 17 00:00:00 2001 From: Yifei SUN <100406743+miaomiao612@users.noreply.github.com> Date: Thu, 10 Nov 2022 04:31:39 +0800 Subject: [PATCH 03/33] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3dfcc62..e178b62 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ +# Voter Canvassing App ## Core Interface Elements ### Layout From 5f81efa4bbacad498cb46c927f422f6eae8ad6d6 Mon Sep 17 00:00:00 2001 From: Yifei SUN <100406743+miaomiao612@users.noreply.github.com> Date: Thu, 10 Nov 2022 04:33:49 +0800 Subject: [PATCH 04/33] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index e178b62..d182552 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ # Voter Canvassing App +### team members: + Yifei Sun, Xuening Zhang, Tom ## Core Interface Elements ### Layout From 6edae647cda710a459e51fbc563ceb96886507ac Mon Sep 17 00:00:00 2001 From: Yifei SUN <100406743+miaomiao612@users.noreply.github.com> Date: Thu, 10 Nov 2022 04:40:54 +0800 Subject: [PATCH 05/33] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d182552..32ae0ab 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Voter Canvassing App ### team members: - Yifei Sun, Xuening Zhang, Tom + Yifei Sun, Xuening Zhang, Tom Sun ## Core Interface Elements ### Layout From b0c70d48c2ffa90db1e4dc1ed548c9578300763d Mon Sep 17 00:00:00 2001 From: Yifei SUN <100406743+miaomiao612@users.noreply.github.com> Date: Thu, 10 Nov 2022 04:42:05 +0800 Subject: [PATCH 06/33] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 32ae0ab..6cdacd0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # Voter Canvassing App ### team members: - Yifei Sun, Xuening Zhang, Tom Sun + *Yifei Sun + *Xuening Zhang + *Tom Sun ## Core Interface Elements ### Layout From 1152a2a480e87f01172a9ccfef6d185c254bfdf6 Mon Sep 17 00:00:00 2001 From: Yifei SUN <100406743+miaomiao612@users.noreply.github.com> Date: Thu, 10 Nov 2022 04:42:21 +0800 Subject: [PATCH 07/33] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6cdacd0..e4675c7 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # Voter Canvassing App ### team members: - *Yifei Sun - *Xuening Zhang - *Tom Sun + * Yifei Sun + * Xuening Zhang + * Tom Sun ## Core Interface Elements ### Layout From 5817d00331ac1132ec701773a8c32f5dd2eaec0a Mon Sep 17 00:00:00 2001 From: Yifei SUN <100406743+miaomiao612@users.noreply.github.com> Date: Thu, 10 Nov 2022 04:42:48 +0800 Subject: [PATCH 08/33] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index e4675c7..9142045 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ * Yifei Sun * Xuening Zhang * Tom Sun + * ... +* ... ## Core Interface Elements ### Layout From c862d76796f61b155468e0975901f010cc8171a9 Mon Sep 17 00:00:00 2001 From: Yifei SUN <100406743+miaomiao612@users.noreply.github.com> Date: Thu, 10 Nov 2022 04:43:15 +0800 Subject: [PATCH 09/33] Update README.md --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 9142045..aa2b713 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,9 @@ # Voter Canvassing App ### team members: - * Yifei Sun - * Xuening Zhang - * Tom Sun - * ... -* ... +* Yifei Sun +* Xuening Zhang +* Tom Sun + ## Core Interface Elements ### Layout From e52279aece2fed9a1cce03ba2fcb883a25d7522c Mon Sep 17 00:00:00 2001 From: Yifei SUN <100406743+miaomiao612@users.noreply.github.com> Date: Thu, 10 Nov 2022 04:44:00 +0800 Subject: [PATCH 10/33] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index aa2b713..c690e2e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Voter Canvassing App -### team members: +### Team members: * Yifei Sun * Xuening Zhang * Tom Sun From 9cf9ffc93146dd5100e6fcd8e3d51a298e1c8484 Mon Sep 17 00:00:00 2001 From: miaomiao612 Date: Thu, 10 Nov 2022 05:57:32 +0800 Subject: [PATCH 11/33] update --- .vscode/settings.json | 3 +++ site/index.html | 23 +++++++++++++++++++++++ site/js/{index.js => main.js} | 0 3 files changed, 26 insertions(+) create mode 100644 .vscode/settings.json rename site/js/{index.js => main.js} (100%) diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..885eeb9 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "liveServer.settings.port": 8081 +} \ No newline at end of file diff --git a/site/index.html b/site/index.html index e69de29..7a8cd6d 100644 --- a/site/index.html +++ b/site/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/site/js/index.js b/site/js/main.js similarity index 100% rename from site/js/index.js rename to site/js/main.js From a9f45f484e51eb091235d9871892d210d0715898 Mon Sep 17 00:00:00 2001 From: miaomiao612 Date: Fri, 11 Nov 2022 20:43:56 +0800 Subject: [PATCH 12/33] update --- .vscode/settings.json | 2 +- site/css/style.css | 1 + site/index.html | 28 +++++++++++++--- site/js/main.js | 20 ++++++++++++ site/js/map.js | 74 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 120 insertions(+), 5 deletions(-) create mode 100644 site/js/map.js diff --git a/.vscode/settings.json b/.vscode/settings.json index 885eeb9..5774974 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,3 @@ { - "liveServer.settings.port": 8081 + "liveServer.settings.port": 8082 } \ No newline at end of file diff --git a/site/css/style.css b/site/css/style.css index e69de29..6b42bb0 100644 --- a/site/css/style.css +++ b/site/css/style.css @@ -0,0 +1 @@ +#voter-Map { height: 300px; } \ No newline at end of file diff --git a/site/index.html b/site/index.html index 7a8cd6d..2b1f061 100644 --- a/site/index.html +++ b/site/index.html @@ -2,7 +2,7 @@ * @Author: miaomiao612 dddoctorr612@gmail.com * @Date: 2022-11-10 05:49:08 * @LastEditors: miaomiao612 dddoctorr612@gmail.com - * @LastEditTime: 2022-11-10 05:55:08 + * @LastEditTime: 2022-11-11 10:54:10 * @FilePath: \voter-canvassing\site\index.html * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE --> @@ -12,12 +12,32 @@ - - + + + + +

Voter Canvassing

+
+
Loading...
+ +
+

+ + +
- + + + + + + \ No newline at end of file diff --git a/site/js/main.js b/site/js/main.js index e69de29..dd9c50b 100644 --- a/site/js/main.js +++ b/site/js/main.js @@ -0,0 +1,20 @@ +/* + * @Author: miaomiao612 dddoctorr612@gmail.com + * @Date: 2022-11-10 05:49:08 + * @LastEditors: miaomiao612 dddoctorr612@gmail.com + * @LastEditTime: 2022-11-11 11:10:11 + * @FilePath: \voter-canvassing\site\js\main.js + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +import { basemap,showVotersOnMap } from './map.js'; + +//convert voters' csv files to json files +fetch('data/voters_lists/3927.csv') +.then(resp=>resp.text()) +.then(text=>{ + const voters=Papa.parse(text,{header:true}); + return voters; +}); + +let voterMap = basemap(); +showVotersOnMap(voters, voterMap); \ No newline at end of file diff --git a/site/js/map.js b/site/js/map.js new file mode 100644 index 0000000..32f49ce --- /dev/null +++ b/site/js/map.js @@ -0,0 +1,74 @@ +/* + * @Author: miaomiao612 dddoctorr612@gmail.com + * @Date: 2022-11-11 03:00:55 + * @LastEditors: miaomiao612 dddoctorr612@gmail.com + * @LastEditTime: 2022-11-11 10:55:29 + * @FilePath: \voter-canvassing\site\js\map.js + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ + +function basemap () { + let voterMap = L.map('voter-Map').setView([39.99893891432174, -75.13162463991333], 13); + +L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { + maxZoom: 19, + attribution: '© OpenStreetMap' +}).addTo(voterMap); + return voterMap; +} + +function makevoterFeature(voters) +{ + return { + "type": "Feature", + "id": schools['sdp_id'], + "properties": { + "school_name": schools["name"], + "address": schools["Street Address"], + "Grade 1": schools['Grade 1'], + "Grade 2": schools['Grade 2'], + "Grade 3": schools['Grade 3'], + "Grade 4": schools['Grade 4'], + "Grade 5": schools['Grade 5'], + "Grade 6": schools['Grade 6'], + "Grade 7": schools['Grade 7'], + "Grade 8": schools['Grade 8'], + "Grade 9": schools['Grade 9'], + "Grade 10": schools['Grade 10'], + "Grade 11": schools['Grade 11'], + "Grade 12": schools['Grade 12'], + "Grade k": schools['Grade K'], + }, + "geometry": schools["geom"], + }; +} +//Use the function to display all the `voters` data on the map. + +function showVotersOnMap(votersToShow, voterMap) { + if (voterMap.voterLayer !== undefined){ + voterMap.removeLayer(voterMap.voterLayer); + } + + const schoolFeatureCollection = { + "type": "FeatureCollection", + "features": votersToShow.map(makeVoterFeature), + }; + + + voterMap.voterLayer = L.geoJSON(voterFeatureCollection, { + pointToLayer: (geoJsonPoint, latlng) => L.circleMarker(latlng), + style:{ + stroke: null, + fillOpacity: 0.7, + radius: 3, + color: '#430184', + }, + }) + .bindTooltip(layer => layer.feature.properties['voter_name']) + .addTo(voterMap); +} +export { + showVotersOnMap, + + basemap +}; \ No newline at end of file From 0810c5e1e2312c2c30b9c91550b91111f47be67f Mon Sep 17 00:00:00 2001 From: miaomiao612 Date: Sun, 13 Nov 2022 08:26:33 +0800 Subject: [PATCH 13/33] update --- package-lock.json | 63 ++++++++++++++++++ package.json | 1 + site/css/style.css | 156 ++++++++++++++++++++++++++++++++++++++++++++- site/index.html | 53 ++++++++++----- site/js/main.js | 7 +- site/js/map.js | 4 +- 6 files changed, 261 insertions(+), 23 deletions(-) diff --git a/package-lock.json b/package-lock.json index 02ef655..c03b390 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "license": "ISC", "devDependencies": { + "babel-plugin-component": "^1.1.1", "eslint": "^8.22.0", "http-server": "^14.1.1", "jest": "^29.0.1", @@ -1536,6 +1537,36 @@ "@babel/core": "^7.8.0" } }, + "node_modules/babel-plugin-component": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-component/-/babel-plugin-component-1.1.1.tgz", + "integrity": "sha512-WUw887kJf2GH80Ng/ZMctKZ511iamHNqPhd9uKo14yzisvV7Wt1EckIrb8oq/uCz3B3PpAW7Xfl7AkTLDYT6ag==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "7.0.0-beta.35" + } + }, + "node_modules/babel-plugin-component/node_modules/@babel/helper-module-imports": { + "version": "7.0.0-beta.35", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0-beta.35.tgz", + "integrity": "sha512-vaC1KyIZSuyWb3Lj277fX0pxivyHwuDU4xZsofqgYAbkDxNieMg2vuhzP5AgMweMY7fCQUMTi+BgPqTLjkxXFg==", + "dev": true, + "dependencies": { + "@babel/types": "7.0.0-beta.35", + "lodash": "^4.2.0" + } + }, + "node_modules/babel-plugin-component/node_modules/@babel/types": { + "version": "7.0.0-beta.35", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.35.tgz", + "integrity": "sha512-y9XT11CozHDgjWcTdxmhSj13rJVXpa5ZXwjjOiTedjaM0ba5ItqdS02t31EhPl7HtOWxsZkYCCUNrSfrOisA6w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2", + "lodash": "^4.2.0", + "to-fast-properties": "^2.0.0" + } + }, "node_modules/babel-plugin-istanbul": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", @@ -7882,6 +7913,38 @@ "slash": "^3.0.0" } }, + "babel-plugin-component": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-component/-/babel-plugin-component-1.1.1.tgz", + "integrity": "sha512-WUw887kJf2GH80Ng/ZMctKZ511iamHNqPhd9uKo14yzisvV7Wt1EckIrb8oq/uCz3B3PpAW7Xfl7AkTLDYT6ag==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "7.0.0-beta.35" + }, + "dependencies": { + "@babel/helper-module-imports": { + "version": "7.0.0-beta.35", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0-beta.35.tgz", + "integrity": "sha512-vaC1KyIZSuyWb3Lj277fX0pxivyHwuDU4xZsofqgYAbkDxNieMg2vuhzP5AgMweMY7fCQUMTi+BgPqTLjkxXFg==", + "dev": true, + "requires": { + "@babel/types": "7.0.0-beta.35", + "lodash": "^4.2.0" + } + }, + "@babel/types": { + "version": "7.0.0-beta.35", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.35.tgz", + "integrity": "sha512-y9XT11CozHDgjWcTdxmhSj13rJVXpa5ZXwjjOiTedjaM0ba5ItqdS02t31EhPl7HtOWxsZkYCCUNrSfrOisA6w==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.2.0", + "to-fast-properties": "^2.0.0" + } + } + } + }, "babel-plugin-istanbul": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", diff --git a/package.json b/package.json index 3a52e5f..480054e 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ }, "homepage": "https://github.com/musa-611-fall-2022/school-explorer#readme", "devDependencies": { + "babel-plugin-component": "^1.1.1", "eslint": "^8.22.0", "http-server": "^14.1.1", "jest": "^29.0.1", diff --git a/site/css/style.css b/site/css/style.css index 6b42bb0..765a7d0 100644 --- a/site/css/style.css +++ b/site/css/style.css @@ -1 +1,155 @@ -#voter-Map { height: 300px; } \ No newline at end of file + +#map { z-index: 0 !important; + height: 700px; + } + + * { + box-sizing: border-box; + } + body { + font-size: 14px; + } + + .v416_3 { + position: absolute; + width: 202px; + height: 31px; + left: 52px; + top: 105px; + background: #989898; + box-shadow: inset 0px 4px 4px rgba(0, 0, 0, 0.25); + } + .v416_5 { + width: 202px; + height: 31px; + background: rgba(152,152,152,1); + opacity: 1; + position: absolute; + top: 105px; + left: 52px; + overflow: hidden; + border: 3px solid #000000; + box-shadow: 0px 8px 8px rgba(0, 0, 0, 0.25); + }:empty::before { + content: attr(placeholder); + } + .v416_7 { + width: 318px; + color: rgba(0,0,0,1); + position: absolute; + top: 67px; + left: 52px; + font-family: McLaren; + font-weight: Bold; + font-size: 24px; + opacity: 1; + text-align: left; + } + .v416_8 { + width: 318px; + color: rgba(0,0,0,1); + position: absolute; + top: 163px; + left: 52px; + font-family: McLaren; + font-weight: Bold; + font-size: 24px; + opacity: 1; + text-align: left; + } + .v416_9 { + width: 407px; + height: 553px; + background: rgba(152,152,152,1); + opacity: 1; + position: absolute; + top: 279px; + left: 52px; + overflow: hidden; + } + .v416_17 { + width: 352px; + height: 23px; + background: rgba(223,223,223,1); + opacity: 1; + position: absolute; + top: 809px; + left: 61px; + overflow: hidden; + } + .v416_10 { + width: 24px; + height: 245px; + background: rgba(92,92,92,1); + opacity: 1; + position: absolute; + top: 331px; + left: 425px; + overflow: hidden; + } + .name { + color: #fff; + } + .name { + color: #fff; + } + .name { + color: #fff; + } + .v416_14 { + width: 352px; + height: 156px; + background: rgba(223,223,223,1); + opacity: 1; + position: absolute; + top: 293px; + left: 61px; + overflow: hidden; + } + .v416_15 { + width: 352px; + height: 156px; + background: rgba(223,223,223,1); + opacity: 1; + position: absolute; + top: 465px; + left: 61px; + overflow: hidden; + } + .v416_16 { + width: 352px; + height: 156px; + background: rgba(223,223,223,1); + opacity: 1; + position: absolute; + top: 637px; + left: 61px; + overflow: hidden; + } + .v416_18 { + width: 416px; + height: 783px; + background: rgba(152,152,152,1); + opacity: 1; + position: absolute; + top: 49px; + left: 982px; + overflow: hidden; + } + .v423_20 { + width: 202px; + height: 31px; + background: rgba(152,152,152,1); + opacity: 1; + position: absolute; + top: 201px; + left: 52px; + overflow: hidden; + border: 3px solid #000000; + box-shadow: 0px 8px 8px rgba(0, 0, 0, 0.25); + }:empty::before { + content: attr(placeholder); + } + + + diff --git a/site/index.html b/site/index.html index 2b1f061..b2db48d 100644 --- a/site/index.html +++ b/site/index.html @@ -2,42 +2,61 @@ * @Author: miaomiao612 dddoctorr612@gmail.com * @Date: 2022-11-10 05:49:08 * @LastEditors: miaomiao612 dddoctorr612@gmail.com - * @LastEditTime: 2022-11-11 10:54:10 + * @LastEditTime: 2022-11-13 07:44:58 * @FilePath: \voter-canvassing\site\index.html * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE --> - - - - + + + voter canvassing + + + - + - -

Voter Canvassing

-
-
Loading...
+ + + +
+ + +
+ List No. +
+
+ Political Parties +
+
+
+
+
+
+
+
+
+
-
-

- -
+ + - - + + + - \ No newline at end of file + + \ No newline at end of file diff --git a/site/js/main.js b/site/js/main.js index dd9c50b..7929523 100644 --- a/site/js/main.js +++ b/site/js/main.js @@ -2,7 +2,7 @@ * @Author: miaomiao612 dddoctorr612@gmail.com * @Date: 2022-11-10 05:49:08 * @LastEditors: miaomiao612 dddoctorr612@gmail.com - * @LastEditTime: 2022-11-11 11:10:11 + * @LastEditTime: 2022-11-13 06:33:11 * @FilePath: \voter-canvassing\site\js\main.js * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE */ @@ -16,5 +16,6 @@ fetch('data/voters_lists/3927.csv') return voters; }); -let voterMap = basemap(); -showVotersOnMap(voters, voterMap); \ No newline at end of file +var voterMap = basemap(); +showVotersOnMap(voters, voterMap); + diff --git a/site/js/map.js b/site/js/map.js index 32f49ce..0a6abbd 100644 --- a/site/js/map.js +++ b/site/js/map.js @@ -2,13 +2,13 @@ * @Author: miaomiao612 dddoctorr612@gmail.com * @Date: 2022-11-11 03:00:55 * @LastEditors: miaomiao612 dddoctorr612@gmail.com - * @LastEditTime: 2022-11-11 10:55:29 + * @LastEditTime: 2022-11-12 08:06:59 * @FilePath: \voter-canvassing\site\js\map.js * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE */ function basemap () { - let voterMap = L.map('voter-Map').setView([39.99893891432174, -75.13162463991333], 13); + let voterMap = L.map('map').setView([39.99893891432174, -75.13162463991333], 13); L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19, From 244cbc630aa00826740dd3f347743427d2338b55 Mon Sep 17 00:00:00 2001 From: miaomiao612 Date: Sun, 13 Nov 2022 08:45:00 +0800 Subject: [PATCH 14/33] update --- site/js/map.js | 53 ++++++++++---------------------------------------- 1 file changed, 10 insertions(+), 43 deletions(-) diff --git a/site/js/map.js b/site/js/map.js index 0a6abbd..225e399 100644 --- a/site/js/map.js +++ b/site/js/map.js @@ -2,7 +2,7 @@ * @Author: miaomiao612 dddoctorr612@gmail.com * @Date: 2022-11-11 03:00:55 * @LastEditors: miaomiao612 dddoctorr612@gmail.com - * @LastEditTime: 2022-11-12 08:06:59 + * @LastEditTime: 2022-11-13 08:44:27 * @FilePath: \voter-canvassing\site\js\map.js * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE */ @@ -17,58 +17,25 @@ L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { return voterMap; } -function makevoterFeature(voters) +//Use this function to get csv files' number +function getListNo(voters) { - return { - "type": "Feature", - "id": schools['sdp_id'], - "properties": { - "school_name": schools["name"], - "address": schools["Street Address"], - "Grade 1": schools['Grade 1'], - "Grade 2": schools['Grade 2'], - "Grade 3": schools['Grade 3'], - "Grade 4": schools['Grade 4'], - "Grade 5": schools['Grade 5'], - "Grade 6": schools['Grade 6'], - "Grade 7": schools['Grade 7'], - "Grade 8": schools['Grade 8'], - "Grade 9": schools['Grade 9'], - "Grade 10": schools['Grade 10'], - "Grade 11": schools['Grade 11'], - "Grade 12": schools['Grade 12'], - "Grade k": schools['Grade K'], - }, - "geometry": schools["geom"], - }; + } -//Use the function to display all the `voters` data on the map. +//Use the function to display the voters' location on the map. function showVotersOnMap(votersToShow, voterMap) { if (voterMap.voterLayer !== undefined){ voterMap.removeLayer(voterMap.voterLayer); } - const schoolFeatureCollection = { - "type": "FeatureCollection", - "features": votersToShow.map(makeVoterFeature), - }; - +//Use this function to display voter list +function showvoterlist(votersToShow, voters){ - voterMap.voterLayer = L.geoJSON(voterFeatureCollection, { - pointToLayer: (geoJsonPoint, latlng) => L.circleMarker(latlng), - style:{ - stroke: null, - fillOpacity: 0.7, - radius: 3, - color: '#430184', - }, - }) - .bindTooltip(layer => layer.feature.properties['voter_name']) - .addTo(voterMap); } + export { + getListNo, showVotersOnMap, - - basemap + showvoterlist }; \ No newline at end of file From 7d830fa2bf7f5aaec5e852f762d97dd79a58677d Mon Sep 17 00:00:00 2001 From: miaomiao612 Date: Mon, 14 Nov 2022 12:22:48 +0800 Subject: [PATCH 15/33] update --- package-lock.json | 13 +++++++++ package.json | 3 ++ site/index.html | 7 +++-- site/js/main.js | 36 ++++++++++++++++-------- site/js/map.js | 70 ++++++++++++++++++++++++++++++++--------------- 5 files changed, 94 insertions(+), 35 deletions(-) diff --git a/package-lock.json b/package-lock.json index c03b390..c85bc50 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,9 @@ "name": "school-explorer", "version": "1.0.0", "license": "ISC", + "dependencies": { + "papaparse": "^5.3.2" + }, "devDependencies": { "babel-plugin-component": "^1.1.1", "eslint": "^8.22.0", @@ -4901,6 +4904,11 @@ "node": ">=6" } }, + "node_modules/papaparse": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.3.2.tgz", + "integrity": "sha512-6dNZu0Ki+gyV0eBsFKJhYr+MdQYAzFUGlBMNj3GNrmHxmz1lfRa24CjFObPXtjcetlOv5Ad299MhIK0znp3afw==" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -10435,6 +10443,11 @@ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, + "papaparse": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.3.2.tgz", + "integrity": "sha512-6dNZu0Ki+gyV0eBsFKJhYr+MdQYAzFUGlBMNj3GNrmHxmz1lfRa24CjFObPXtjcetlOv5Ad299MhIK0znp3afw==" + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", diff --git a/package.json b/package.json index 480054e..b57c52e 100644 --- a/package.json +++ b/package.json @@ -28,5 +28,8 @@ "jest-puppeteer": "^6.1.1", "stylelint": "^14.11.0", "stylelint-config-standard": "^28.0.0" + }, + "dependencies": { + "papaparse": "^5.3.2" } } diff --git a/site/index.html b/site/index.html index b2db48d..3d734cc 100644 --- a/site/index.html +++ b/site/index.html @@ -2,7 +2,7 @@ * @Author: miaomiao612 dddoctorr612@gmail.com * @Date: 2022-11-10 05:49:08 * @LastEditors: miaomiao612 dddoctorr612@gmail.com - * @LastEditTime: 2022-11-13 07:44:58 + * @LastEditTime: 2022-11-14 11:02:26 * @FilePath: \voter-canvassing\site\index.html * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE --> @@ -20,12 +20,14 @@ + + -
+
@@ -45,6 +47,7 @@
+ diff --git a/site/js/main.js b/site/js/main.js index 7929523..c3ac972 100644 --- a/site/js/main.js +++ b/site/js/main.js @@ -2,20 +2,34 @@ * @Author: miaomiao612 dddoctorr612@gmail.com * @Date: 2022-11-10 05:49:08 * @LastEditors: miaomiao612 dddoctorr612@gmail.com - * @LastEditTime: 2022-11-13 06:33:11 + * @LastEditTime: 2022-11-14 10:56:31 * @FilePath: \voter-canvassing\site\js\main.js * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE */ -import { basemap,showVotersOnMap } from './map.js'; +import { initMap, showVotersOnMap } from './map.js'; -//convert voters' csv files to json files -fetch('data/voters_lists/3927.csv') -.then(resp=>resp.text()) -.then(text=>{ - const voters=Papa.parse(text,{header:true}); - return voters; -}); +let voterMap=initMap; -var voterMap = basemap(); -showVotersOnMap(voters, voterMap); +//convert csv to json +function cvstojson (map, neighbor, onFailure){ + fetch(`./data/voters_lists/${neighbor}.csv`) + .then(response => { + if (response.status === 200) { + const data = response.text(); + return data; + } else { + alert('Oh no, I failed to download the data.'); + if (onFailure) { onFailure() } + } + }) + .then(v => Papa.parse(v, { delimiter:"," })) + .catch(err => console.log(err)) + .then(result => { + let v = result.data.slice(1, result.data.length-1); + return v; + }) + .then(result => showVotersOnMap(map, result)); + } + +window.voterMap=voterMap; diff --git a/site/js/map.js b/site/js/map.js index 225e399..e6b0b75 100644 --- a/site/js/map.js +++ b/site/js/map.js @@ -2,40 +2,66 @@ * @Author: miaomiao612 dddoctorr612@gmail.com * @Date: 2022-11-11 03:00:55 * @LastEditors: miaomiao612 dddoctorr612@gmail.com - * @LastEditTime: 2022-11-13 08:44:27 + * @LastEditTime: 2022-11-14 11:02:43 * @FilePath: \voter-canvassing\site\js\map.js * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE */ +function initMap() { + const map = L.map('map', { maxZoom: 22, preferCanvas: true }).setView([39.95, -75.16], 13); + + const mapboxAccount = 'mapbox'; + const mapboxStyle = 'light-v10'; + const mapboxToken = 'pk.eyJ1IjoibWp1bWJlLXRlc3QiLCJhIjoiY2w3ZTh1NTIxMTgxNTQwcGhmODU2NW5kaSJ9.pBPd19nWO-Gt-vTf1pOHBA'; + L.tileLayer(`https://api.mapbox.com/styles/v1/${mapboxAccount}/${mapboxStyle}/tiles/256/{z}/{x}/{y}@2x?access_token=${mapboxToken}`, { + maxZoom: 19, + attribution: '© Mapbox © OpenStreetMap Improve this map', + }).addTo(map); + -function basemap () { - let voterMap = L.map('map').setView([39.99893891432174, -75.13162463991333], 13); -L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { - maxZoom: 19, - attribution: '© OpenStreetMap' -}).addTo(voterMap); - return voterMap; -} -//Use this function to get csv files' number -function getListNo(voters) +//convert json to a geojson-like feature +function makevoterFeature(voter) { + return { + "type": "Feature", + "id": voter['ID Number'], + "properties": { + "Last Name":voter['Last Name'], + "First Name": voter['First Name'], + "Registration Date": voter['Registration Date'], + "Voter Status": voter['Voter Status'], + "Party Code": voter['Party Code'], + }, + "geometry": + { "type": "Point", + "coordinates":voter['TIGER/Line Lng/Lat'], + + }, + }; } //Use the function to display the voters' location on the map. -function showVotersOnMap(votersToShow, voterMap) { - if (voterMap.voterLayer !== undefined){ - voterMap.removeLayer(voterMap.voterLayer); +function showVotersOnMap(votersToShow, Map) { + if (Map.voterLayer !== undefined){ + Map.removeLayer(Map.voterLayer); } -//Use this function to display voter list -function showvoterlist(votersToShow, voters){ - + const voterFeatureCollection = { + "type": "FeatureCollection", + "features": votersToShow.map(makevoterFeature), + }; + map.voterLayer = L.geoJSON(null, { + pointToLayer: (feature, latlng) => L.circleMarker(latlng), + style: { + fillColor: '#83bf15', + fillOpacity: 0.3, + stroke: false, + }, + }).addTo(map); } -export { - getListNo, - showVotersOnMap, - showvoterlist -}; \ No newline at end of file +export{ + initMap, +} \ No newline at end of file From 793af9013586847c9dd91098a3d2e5482d24b13d Mon Sep 17 00:00:00 2001 From: miaomiao612 Date: Tue, 15 Nov 2022 13:16:25 +0800 Subject: [PATCH 16/33] update --- site/css/style.css | 75 ++++++++++++++++++++++++++++++++-------------- site/index.html | 22 +++++++------- site/js/main.js | 23 ++++++++++---- site/js/map.js | 43 +++++++++++++++++++------- 4 files changed, 114 insertions(+), 49 deletions(-) diff --git a/site/css/style.css b/site/css/style.css index 765a7d0..698bf10 100644 --- a/site/css/style.css +++ b/site/css/style.css @@ -1,6 +1,6 @@ -#map { z-index: 0 !important; - height: 700px; +#voterMap { z-index: 0 !important; + height: 650px; } * { @@ -10,22 +10,13 @@ font-size: 14px; } - .v416_3 { - position: absolute; - width: 202px; - height: 31px; - left: 52px; - top: 105px; - background: #989898; - box-shadow: inset 0px 4px 4px rgba(0, 0, 0, 0.25); - } - .v416_5 { + .listNo_inputbox{ width: 202px; height: 31px; - background: rgba(152,152,152,1); + background: rgb(203, 203, 203); opacity: 1; position: absolute; - top: 105px; + top: 115px; left: 52px; overflow: hidden; border: 3px solid #000000; @@ -33,27 +24,27 @@ }:empty::before { content: attr(placeholder); } - .v416_7 { + .listNo { width: 318px; color: rgba(0,0,0,1); position: absolute; - top: 67px; + top: 90px; left: 52px; font-family: McLaren; font-weight: Bold; - font-size: 24px; + font-size: 20px; opacity: 1; text-align: left; } - .v416_8 { + .pp { width: 318px; color: rgba(0,0,0,1); position: absolute; - top: 163px; + top: 175px; left: 52px; font-family: McLaren; font-weight: Bold; - font-size: 24px; + font-size: 20px; opacity: 1; text-align: left; } @@ -136,10 +127,10 @@ left: 982px; overflow: hidden; } - .v423_20 { + .pp_inputbox { width: 202px; height: 31px; - background: rgba(152,152,152,1); + background: rgba(203, 203, 203); opacity: 1; position: absolute; top: 201px; @@ -150,6 +141,46 @@ }:empty::before { content: attr(placeholder); } + .button1{ + display: inline-block; + background-color: #525252; + border-radius: 5px; + border: 2px double #000000; + color: #eeeeee; + text-align: center; + font-size: 15px; + padding: 5px; + width: 65px; + -webkit-transition: all 0.5s; + -moz-transition: all 0.5s; + -o-transition: all 0.5s; + transition: all 0.5s; + cursor: pointer; + margin: 3px; + position: absolute; + top: 112px; + left: 270px; + } + .button2{ + display: inline-block; + background-color: #525252; + border-radius: 5px; + border: 2px double #000000; + color: #eeeeee; + text-align: center; + font-size: 15px; + padding: 5px; + width: 65px; + -webkit-transition: all 0.5s; + -moz-transition: all 0.5s; + -o-transition: all 0.5s; + transition: all 0.5s; + cursor: pointer; + margin: 3px; + position: absolute; + top: 198px; + left: 270px; + } diff --git a/site/index.html b/site/index.html index 3d734cc..ad3ebfc 100644 --- a/site/index.html +++ b/site/index.html @@ -2,40 +2,38 @@ * @Author: miaomiao612 dddoctorr612@gmail.com * @Date: 2022-11-10 05:49:08 * @LastEditors: miaomiao612 dddoctorr612@gmail.com - * @LastEditTime: 2022-11-14 11:02:26 + * @LastEditTime: 2022-11-15 13:02:55 * @FilePath: \voter-canvassing\site\index.html * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE --> + voter canvassing - - - - - + +
-
-
- List No. -
+ List No. +
+
- Political Parties -
+ Political Parties +
+
diff --git a/site/js/main.js b/site/js/main.js index c3ac972..ed179ef 100644 --- a/site/js/main.js +++ b/site/js/main.js @@ -2,17 +2,28 @@ * @Author: miaomiao612 dddoctorr612@gmail.com * @Date: 2022-11-10 05:49:08 * @LastEditors: miaomiao612 dddoctorr612@gmail.com - * @LastEditTime: 2022-11-14 10:56:31 + * @LastEditTime: 2022-11-15 11:17:39 * @FilePath: \voter-canvassing\site\js\main.js * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE */ + +// voter canvassing App +// ============================ + +// The _main.js_ module defines the primary functionality of the app, and serves +// as the cross-component coordinator. Additional functionality is found in +// individual component modules: +// * [map.js]: for behavior related to the map + import { initMap, showVotersOnMap } from './map.js'; -let voterMap=initMap; +let voterMap=initMap(); +let votersToShow = document.querySelector('#listNo'); + //convert csv to json -function cvstojson (map, neighbor, onFailure){ - fetch(`./data/voters_lists/${neighbor}.csv`) +function csvtojson (voterMap, votersToShow, onFailure){ + fetch(`./data/voters_lists/${votersToShow}.csv`) .then(response => { if (response.status === 200) { const data = response.text(); @@ -28,8 +39,10 @@ function cvstojson (map, neighbor, onFailure){ let v = result.data.slice(1, result.data.length-1); return v; }) - .then(result => showVotersOnMap(map, result)); + .then(result => showVotersOnMap(result, voterMap)); } + csvtojson (voterMap, votersToShow ); + showVotersOnMap(votersToShow, voterMap); window.voterMap=voterMap; diff --git a/site/js/map.js b/site/js/map.js index e6b0b75..d89be8d 100644 --- a/site/js/map.js +++ b/site/js/map.js @@ -2,12 +2,20 @@ * @Author: miaomiao612 dddoctorr612@gmail.com * @Date: 2022-11-11 03:00:55 * @LastEditors: miaomiao612 dddoctorr612@gmail.com - * @LastEditTime: 2022-11-14 11:02:43 + * @LastEditTime: 2022-11-15 13:15:14 * @FilePath: \voter-canvassing\site\js\map.js * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE */ +function onvoterClicked(evt) { + console.log(evt); + const voter = evt.layer.feature; + + const voterSelectedEvent = new CustomEvent('voter-selected', { detail: { voter } }); + window.dispatchEvent(voterSelectedEvent); +} + function initMap() { - const map = L.map('map', { maxZoom: 22, preferCanvas: true }).setView([39.95, -75.16], 13); + const map = L.map('voterMap', { maxZoom: 22, preferCanvas: true }).setView([39.95, -75.16], 13); const mapboxAccount = 'mapbox'; const mapboxStyle = 'light-v10'; @@ -16,8 +24,21 @@ function initMap() { maxZoom: 19, attribution: '© Mapbox © OpenStreetMap Improve this map', }).addTo(map); + map.treeLayer = L.geoJSON(null, { + pointToLayer: (feature, latlng) => L.circleMarker(latlng), + style: { + fillColor: '#83bf15', + fillOpacity: 0.3, + stroke: false, + }, + }).addTo(map); + + map.treeLayer.addEventListener('click', onvoterClicked); + map.positionLayer = L.geoJSON(null).addTo(map); + return map; +} //convert json to a geojson-like feature @@ -43,16 +64,16 @@ function makevoterFeature(voter) } //Use the function to display the voters' location on the map. -function showVotersOnMap(votersToShow, Map) { - if (Map.voterLayer !== undefined){ - Map.removeLayer(Map.voterLayer); +function showVotersOnMap(votersToShow, map) { + if (map.voterLayer !== undefined){ + map.removeLayer(map.voterLayer); } const voterFeatureCollection = { "type": "FeatureCollection", "features": votersToShow.map(makevoterFeature), }; - map.voterLayer = L.geoJSON(null, { + map.voterLayer = L.geoJSON(voterFeatureCollection, { pointToLayer: (feature, latlng) => L.circleMarker(latlng), style: { fillColor: '#83bf15', @@ -60,8 +81,10 @@ function showVotersOnMap(votersToShow, Map) { stroke: false, }, }).addTo(map); -} + } -export{ - initMap, -} \ No newline at end of file + export{ + initMap, + showVotersOnMap, + makevoterFeature, +}; \ No newline at end of file From 3ad11322e145c8329e0c3df7736cae3bcbeca228 Mon Sep 17 00:00:00 2001 From: miaomiao612 Date: Wed, 16 Nov 2022 00:31:42 +0800 Subject: [PATCH 17/33] update --- site/index.html | 14 +++++++------- site/js/main.js | 37 +++++++++++-------------------------- site/js/managedata.js | 27 +++++++++++++++++++++++++++ site/js/map.js | 26 ++++++++++++++++---------- site/js/papaparse.min.js | 7 +++++++ 5 files changed, 68 insertions(+), 43 deletions(-) create mode 100644 site/js/managedata.js create mode 100644 site/js/papaparse.min.js diff --git a/site/index.html b/site/index.html index ad3ebfc..bb9f537 100644 --- a/site/index.html +++ b/site/index.html @@ -2,7 +2,7 @@ * @Author: miaomiao612 dddoctorr612@gmail.com * @Date: 2022-11-10 05:49:08 * @LastEditors: miaomiao612 dddoctorr612@gmail.com - * @LastEditTime: 2022-11-15 13:02:55 + * @LastEditTime: 2022-11-16 00:25:40 * @FilePath: \voter-canvassing\site\index.html * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE --> @@ -28,12 +28,12 @@ List No. -
- + +
Political Parties -
- + +
@@ -46,14 +46,14 @@ - + - + diff --git a/site/js/main.js b/site/js/main.js index ed179ef..7dfffd7 100644 --- a/site/js/main.js +++ b/site/js/main.js @@ -2,7 +2,7 @@ * @Author: miaomiao612 dddoctorr612@gmail.com * @Date: 2022-11-10 05:49:08 * @LastEditors: miaomiao612 dddoctorr612@gmail.com - * @LastEditTime: 2022-11-15 11:17:39 + * @LastEditTime: 2022-11-16 00:12:49 * @FilePath: \voter-canvassing\site\js\main.js * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE */ @@ -15,34 +15,19 @@ // individual component modules: // * [map.js]: for behavior related to the map -import { initMap, showVotersOnMap } from './map.js'; +import { initMap} from './map.js'; +import {csvtojson} from './managedata.js'; + let voterMap=initMap(); let votersToShow = document.querySelector('#listNo'); +//let search1 = document.querySelector('#button1'); +let btn = document.getElementById("search1"); + // add event listener for the button, for action "click" +btn.addEventListener("click", csvtojson(votersToShow, voterMap)); -//convert csv to json -function csvtojson (voterMap, votersToShow, onFailure){ - fetch(`./data/voters_lists/${votersToShow}.csv`) - .then(response => { - if (response.status === 200) { - const data = response.text(); - return data; - } else { - alert('Oh no, I failed to download the data.'); - if (onFailure) { onFailure() } - } - }) - .then(v => Papa.parse(v, { delimiter:"," })) - .catch(err => console.log(err)) - .then(result => { - let v = result.data.slice(1, result.data.length-1); - return v; - }) - .then(result => showVotersOnMap(result, voterMap)); - } - - csvtojson (voterMap, votersToShow ); - showVotersOnMap(votersToShow, voterMap); -window.voterMap=voterMap; + //Search(voterMap, search1, votersToShow); +window.voterMap=voterMap; +window.votersToShow=votersToShow; diff --git a/site/js/managedata.js b/site/js/managedata.js new file mode 100644 index 0000000..900fb46 --- /dev/null +++ b/site/js/managedata.js @@ -0,0 +1,27 @@ +import { showVotersOnMap } from './map.js'; + +//convert csv to json +function csvtojson ( map, votersToShow, onFailure){ + fetch(`./data/voters_lists/${votersToShow}.csv`) + .then(response => { + if (response.status === 200) { + const data = response.text(); + return data; + } else { + alert('Oh no, I failed to download the data.'); + if (onFailure) { onFailure() } + } + }) + .then(v => Papa.parse(v, { delimiter:"," })) + .catch(err => console.log(err)) + .then(result => { + let v = result.data.slice(1, result.data.length-1); + return v; + }) + .then(result => showVotersOnMap( result, map)); + + } + +export{ + csvtojson, +}; \ No newline at end of file diff --git a/site/js/map.js b/site/js/map.js index d89be8d..cfa1001 100644 --- a/site/js/map.js +++ b/site/js/map.js @@ -2,10 +2,12 @@ * @Author: miaomiao612 dddoctorr612@gmail.com * @Date: 2022-11-11 03:00:55 * @LastEditors: miaomiao612 dddoctorr612@gmail.com - * @LastEditTime: 2022-11-15 13:15:14 + * @LastEditTime: 2022-11-16 00:15:05 * @FilePath: \voter-canvassing\site\js\map.js * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE */ + + function onvoterClicked(evt) { console.log(evt); const voter = evt.layer.feature; @@ -40,7 +42,6 @@ function initMap() { return map; } - //convert json to a geojson-like feature function makevoterFeature(voter) { @@ -64,27 +65,32 @@ function makevoterFeature(voter) } //Use the function to display the voters' location on the map. -function showVotersOnMap(votersToShow, map) { - if (map.voterLayer !== undefined){ - map.removeLayer(map.voterLayer); +function showVotersOnMap(votersToShow, voterMap) { + if (voterMap.voterLayer !== undefined){ + voterMap.removeLayer(voterMap.voterLayer); } const voterFeatureCollection = { "type": "FeatureCollection", "features": votersToShow.map(makevoterFeature), }; - map.voterLayer = L.geoJSON(voterFeatureCollection, { + voterMap.voterLayer = L.geoJSON(voterFeatureCollection, { pointToLayer: (feature, latlng) => L.circleMarker(latlng), style: { fillColor: '#83bf15', fillOpacity: 0.3, stroke: false, }, - }).addTo(map); + }).addTo(voterMap); } - export{ + +//use this function to search the voters by listNo + + + +export{ initMap, showVotersOnMap, - makevoterFeature, -}; \ No newline at end of file + +}; diff --git a/site/js/papaparse.min.js b/site/js/papaparse.min.js new file mode 100644 index 0000000..14c98ff --- /dev/null +++ b/site/js/papaparse.min.js @@ -0,0 +1,7 @@ +/* @license +Papa Parse +v5.0.2 +https://github.com/mholt/PapaParse +License: MIT +*/ +!function(e,t){"function"==typeof define&&define.amd?define([],t):"object"==typeof module&&"undefined"!=typeof exports?module.exports=t():e.Papa=t()}(this,function s(){"use strict";var f="undefined"!=typeof self?self:"undefined"!=typeof window?window:void 0!==f?f:{};var n=!f.document&&!!f.postMessage,o=n&&/blob:/i.test((f.location||{}).protocol),a={},h=0,b={parse:function(e,t){var r=(t=t||{}).dynamicTyping||!1;q(r)&&(t.dynamicTypingFunction=r,r={});if(t.dynamicTyping=r,t.transform=!!q(t.transform)&&t.transform,t.worker&&b.WORKERS_SUPPORTED){var i=function(){if(!b.WORKERS_SUPPORTED)return!1;var e=(r=f.URL||f.webkitURL||null,i=s.toString(),b.BLOB_URL||(b.BLOB_URL=r.createObjectURL(new Blob(["(",i,")();"],{type:"text/javascript"})))),t=new f.Worker(e);var r,i;return t.onmessage=_,t.id=h++,a[t.id]=t}();return i.userStep=t.step,i.userChunk=t.chunk,i.userComplete=t.complete,i.userError=t.error,t.step=q(t.step),t.chunk=q(t.chunk),t.complete=q(t.complete),t.error=q(t.error),delete t.worker,void i.postMessage({input:e,config:t,workerId:i.id})}var n=null;b.NODE_STREAM_INPUT,"string"==typeof e?n=t.download?new l(t):new p(t):!0===e.readable&&q(e.read)&&q(e.on)?n=new m(t):(f.File&&e instanceof File||e instanceof Object)&&(n=new c(t));return n.stream(e)},unparse:function(e,t){var i=!1,_=!0,g=",",v="\r\n",n='"',s=n+n,r=!1,a=null;!function(){if("object"!=typeof t)return;"string"!=typeof t.delimiter||b.BAD_DELIMITERS.filter(function(e){return-1!==t.delimiter.indexOf(e)}).length||(g=t.delimiter);("boolean"==typeof t.quotes||Array.isArray(t.quotes))&&(i=t.quotes);"boolean"!=typeof t.skipEmptyLines&&"string"!=typeof t.skipEmptyLines||(r=t.skipEmptyLines);"string"==typeof t.newline&&(v=t.newline);"string"==typeof t.quoteChar&&(n=t.quoteChar);"boolean"==typeof t.header&&(_=t.header);if(Array.isArray(t.columns)){if(0===t.columns.length)throw new Error("Option columns is empty");a=t.columns}void 0!==t.escapeChar&&(s=t.escapeChar+n)}();var o=new RegExp(U(n),"g");"string"==typeof e&&(e=JSON.parse(e));if(Array.isArray(e)){if(!e.length||Array.isArray(e[0]))return u(null,e,r);if("object"==typeof e[0])return u(a||h(e[0]),e,r)}else if("object"==typeof e)return"string"==typeof e.data&&(e.data=JSON.parse(e.data)),Array.isArray(e.data)&&(e.fields||(e.fields=e.meta&&e.meta.fields),e.fields||(e.fields=Array.isArray(e.data[0])?e.fields:h(e.data[0])),Array.isArray(e.data[0])||"object"==typeof e.data[0]||(e.data=[e.data])),u(e.fields||[],e.data||[],r);throw new Error("Unable to serialize unrecognized input");function h(e){if("object"!=typeof e)return[];var t=[];for(var r in e)t.push(r);return t}function u(e,t,r){var i="";"string"==typeof e&&(e=JSON.parse(e)),"string"==typeof t&&(t=JSON.parse(t));var n=Array.isArray(e)&&0=this._config.preview;if(o)f.postMessage({results:n,workerId:b.WORKER_ID,finished:a});else if(q(this._config.chunk)&&!t){if(this._config.chunk(n,this._handle),this._handle.paused()||this._handle.aborted())return void(this._halted=!0);n=void 0,this._completeResults=void 0}return this._config.step||this._config.chunk||(this._completeResults.data=this._completeResults.data.concat(n.data),this._completeResults.errors=this._completeResults.errors.concat(n.errors),this._completeResults.meta=n.meta),this._completed||!a||!q(this._config.complete)||n&&n.meta.aborted||(this._config.complete(this._completeResults,this._input),this._completed=!0),a||n&&n.meta.paused||this._nextChunk(),n}this._halted=!0},this._sendError=function(e){q(this._config.error)?this._config.error(e):o&&this._config.error&&f.postMessage({workerId:b.WORKER_ID,error:e,finished:!1})}}function l(e){var i;(e=e||{}).chunkSize||(e.chunkSize=b.RemoteChunkSize),u.call(this,e),this._nextChunk=n?function(){this._readChunk(),this._chunkLoaded()}:function(){this._readChunk()},this.stream=function(e){this._input=e,this._nextChunk()},this._readChunk=function(){if(this._finished)this._chunkLoaded();else{if(i=new XMLHttpRequest,this._config.withCredentials&&(i.withCredentials=this._config.withCredentials),n||(i.onload=y(this._chunkLoaded,this),i.onerror=y(this._chunkError,this)),i.open("GET",this._input,!n),this._config.downloadRequestHeaders){var e=this._config.downloadRequestHeaders;for(var t in e)i.setRequestHeader(t,e[t])}if(this._config.chunkSize){var r=this._start+this._config.chunkSize-1;i.setRequestHeader("Range","bytes="+this._start+"-"+r)}try{i.send()}catch(e){this._chunkError(e.message)}n&&0===i.status?this._chunkError():this._start+=this._config.chunkSize}},this._chunkLoaded=function(){4===i.readyState&&(i.status<200||400<=i.status?this._chunkError():(this._finished=!this._config.chunkSize||this._start>function(e){var t=e.getResponseHeader("Content-Range");if(null===t)return-1;return parseInt(t.substr(t.lastIndexOf("/")+1))}(i),this.parseChunk(i.responseText)))},this._chunkError=function(e){var t=i.statusText||e;this._sendError(new Error(t))}}function c(e){var i,n;(e=e||{}).chunkSize||(e.chunkSize=b.LocalChunkSize),u.call(this,e);var s="undefined"!=typeof FileReader;this.stream=function(e){this._input=e,n=e.slice||e.webkitSlice||e.mozSlice,s?((i=new FileReader).onload=y(this._chunkLoaded,this),i.onerror=y(this._chunkError,this)):i=new FileReaderSync,this._nextChunk()},this._nextChunk=function(){this._finished||this._config.preview&&!(this._rowCount=this._input.size,this.parseChunk(e.target.result)},this._chunkError=function(){this._sendError(i.error)}}function p(e){var r;u.call(this,e=e||{}),this.stream=function(e){return r=e,this._nextChunk()},this._nextChunk=function(){if(!this._finished){var e=this._config.chunkSize,t=e?r.substr(0,e):r;return r=e?r.substr(e):"",this._finished=!r,this.parseChunk(t)}}}function m(e){u.call(this,e=e||{});var t=[],r=!0,i=!1;this.pause=function(){u.prototype.pause.apply(this,arguments),this._input.pause()},this.resume=function(){u.prototype.resume.apply(this,arguments),this._input.resume()},this.stream=function(e){this._input=e,this._input.on("data",this._streamData),this._input.on("end",this._streamEnd),this._input.on("error",this._streamError)},this._checkIsFinished=function(){i&&1===t.length&&(this._finished=!0)},this._nextChunk=function(){this._checkIsFinished(),t.length?this.parseChunk(t.shift()):r=!0},this._streamData=y(function(e){try{t.push("string"==typeof e?e:e.toString(this._config.encoding)),r&&(r=!1,this._checkIsFinished(),this.parseChunk(t.shift()))}catch(e){this._streamError(e)}},this),this._streamError=y(function(e){this._streamCleanUp(),this._sendError(e)},this),this._streamEnd=y(function(){this._streamCleanUp(),i=!0,this._streamData("")},this),this._streamCleanUp=y(function(){this._input.removeListener("data",this._streamData),this._input.removeListener("end",this._streamEnd),this._input.removeListener("error",this._streamError)},this)}function r(g){var a,o,h,i=Math.pow(2,53),n=-i,s=/^\s*-?(\d*\.?\d+|\d+\.?\d*)(e[-+]?\d+)?\s*$/i,u=/(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))/,t=this,r=0,f=0,d=!1,e=!1,l=[],c={data:[],errors:[],meta:{}};if(q(g.step)){var p=g.step;g.step=function(e){if(c=e,_())m();else{if(m(),0===c.data.length)return;r+=e.data.length,g.preview&&r>g.preview?o.abort():p(c,t)}}}function v(e){return"greedy"===g.skipEmptyLines?""===e.join("").trim():1===e.length&&0===e[0].length}function m(){if(c&&h&&(k("Delimiter","UndetectableDelimiter","Unable to auto-detect delimiting character; defaulted to '"+b.DefaultDelimiter+"'"),h=!1),g.skipEmptyLines)for(var e=0;e=l.length?"__parsed_extra":l[r]),g.transform&&(s=g.transform(s,n)),s=y(n,s),"__parsed_extra"===n?(i[n]=i[n]||[],i[n].push(s)):i[n]=s}return g.header&&(r>l.length?k("FieldMismatch","TooManyFields","Too many fields: expected "+l.length+" fields but parsed "+r,f+t):r=i.length/2?"\r\n":"\r"}(e,i)),h=!1,g.delimiter)q(g.delimiter)&&(g.delimiter=g.delimiter(e),c.meta.delimiter=g.delimiter);else{var n=function(e,t,r,i,n){var s,a,o,h;n=n||[",","\t","|",";",b.RECORD_SEP,b.UNIT_SEP];for(var u=0;u=L)return R(!0)}else for(g=M,M++;;){if(-1===(g=a.indexOf(O,g+1)))return t||u.push({type:"Quotes",code:"MissingQuotes",message:"Quoted field unterminated",row:h.length,index:M}),w();if(g===i-1)return w(a.substring(M,g).replace(_,O));if(O!==z||a[g+1]!==z){if(O===z||0===g||a[g-1]!==z){var y=E(-1===m?p:Math.min(p,m));if(a[g+1+y]===D){f.push(a.substring(M,g).replace(_,O)),a[M=g+1+y+e]!==O&&(g=a.indexOf(O,M)),p=a.indexOf(D,M),m=a.indexOf(I,M);break}var k=E(m);if(a.substr(g+1+k,n)===I){if(f.push(a.substring(M,g).replace(_,O)),C(g+1+k+n),p=a.indexOf(D,M),g=a.indexOf(O,M),o&&(S(),j))return R();if(L&&h.length>=L)return R(!0);break}u.push({type:"Quotes",code:"InvalidQuotes",message:"Trailing quote on quoted field is malformed",row:h.length,index:M}),g++}}else g++}return w();function b(e){h.push(e),d=M}function E(e){var t=0;if(-1!==e){var r=a.substring(g+1,e);r&&""===r.trim()&&(t=r.length)}return t}function w(e){return t||(void 0===e&&(e=a.substr(M)),f.push(e),M=i,b(f),o&&S()),R()}function C(e){M=e,b(f),f=[],m=a.indexOf(I,M)}function R(e,t){return{data:t||!1?h[0]:h,errors:u,meta:{delimiter:D,linebreak:I,aborted:j,truncated:!!e,cursor:d+(r||0)}}}function S(){A(R(void 0,!0)),h=[],u=[]}function x(e,t,r){var i={nextDelim:void 0,quoteSearch:void 0},n=a.indexOf(O,t+1);if(t Date: Wed, 16 Nov 2022 01:24:42 +0800 Subject: [PATCH 18/33] Create 1 --- site/data/1 | 1 + 1 file changed, 1 insertion(+) create mode 100644 site/data/1 diff --git a/site/data/1 b/site/data/1 new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/site/data/1 @@ -0,0 +1 @@ + From a7eb3f1cd123259bb123e676bc2cbd9742e97334 Mon Sep 17 00:00:00 2001 From: miaomiao612 Date: Wed, 16 Nov 2022 02:56:46 +0800 Subject: [PATCH 19/33] update --- site/index.html | 6 +++--- site/js/main.js | 17 +++++++++-------- site/js/managedata.js | 3 ++- site/js/map.js | 14 ++++++++++---- 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/site/index.html b/site/index.html index bb9f537..21e927c 100644 --- a/site/index.html +++ b/site/index.html @@ -2,7 +2,7 @@ * @Author: miaomiao612 dddoctorr612@gmail.com * @Date: 2022-11-10 05:49:08 * @LastEditors: miaomiao612 dddoctorr612@gmail.com - * @LastEditTime: 2022-11-16 00:25:40 + * @LastEditTime: 2022-11-16 01:13:17 * @FilePath: \voter-canvassing\site\index.html * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE --> @@ -28,11 +28,11 @@ List No. - +
Political Parties - +
diff --git a/site/js/main.js b/site/js/main.js index 7dfffd7..fa56243 100644 --- a/site/js/main.js +++ b/site/js/main.js @@ -2,7 +2,7 @@ * @Author: miaomiao612 dddoctorr612@gmail.com * @Date: 2022-11-10 05:49:08 * @LastEditors: miaomiao612 dddoctorr612@gmail.com - * @LastEditTime: 2022-11-16 00:12:49 + * @LastEditTime: 2022-11-16 02:55:08 * @FilePath: \voter-canvassing\site\js\main.js * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE */ @@ -15,19 +15,20 @@ // individual component modules: // * [map.js]: for behavior related to the map -import { initMap} from './map.js'; -import {csvtojson} from './managedata.js'; +import { initMap, Search } from './map.js'; +//import { csvtojson } from './managedata.js'; let voterMap=initMap(); let votersToShow = document.querySelector('#listNo'); -//let search1 = document.querySelector('#button1'); +let search = document.querySelector('#search1'); -let btn = document.getElementById("search1"); - // add event listener for the button, for action "click" -btn.addEventListener("click", csvtojson(votersToShow, voterMap)); +//let btn = document.getElementById("search1"); +//btn.addEventListener("click", csvtojson(voterMap, votersToShow)); - //Search(voterMap, search1, votersToShow); +Search(voterMap, search, votersToShow); + window.voterMap=voterMap; window.votersToShow=votersToShow; +window.search=search; diff --git a/site/js/managedata.js b/site/js/managedata.js index 900fb46..34960a9 100644 --- a/site/js/managedata.js +++ b/site/js/managedata.js @@ -1,5 +1,4 @@ import { showVotersOnMap } from './map.js'; - //convert csv to json function csvtojson ( map, votersToShow, onFailure){ fetch(`./data/voters_lists/${votersToShow}.csv`) @@ -17,9 +16,11 @@ function csvtojson ( map, votersToShow, onFailure){ .then(result => { let v = result.data.slice(1, result.data.length-1); return v; + }) .then(result => showVotersOnMap( result, map)); + } export{ diff --git a/site/js/map.js b/site/js/map.js index cfa1001..01bb940 100644 --- a/site/js/map.js +++ b/site/js/map.js @@ -2,11 +2,11 @@ * @Author: miaomiao612 dddoctorr612@gmail.com * @Date: 2022-11-11 03:00:55 * @LastEditors: miaomiao612 dddoctorr612@gmail.com - * @LastEditTime: 2022-11-16 00:15:05 + * @LastEditTime: 2022-11-16 02:51:23 * @FilePath: \voter-canvassing\site\js\map.js * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE */ - +import{ csvtojson } from './managedata.js'; function onvoterClicked(evt) { console.log(evt); @@ -58,7 +58,7 @@ function makevoterFeature(voter) }, "geometry": { "type": "Point", - "coordinates":voter['TIGER/Line Lng/Lat'], + "coordinates":[voter['28'].substr(0, 18), voter['28'].substr(19, voter.length)], }, }; @@ -86,11 +86,17 @@ function showVotersOnMap(votersToShow, voterMap) { //use this function to search the voters by listNo +function Search (map, search, votersToShow) { + search.addEventListener('click', () => { + let votersToShow1 = votersToShow.value; + csvtojson(map, votersToShow1); + }); - +} export{ initMap, showVotersOnMap, + Search, }; From e62c10df3e1933d11dfd09f09c1cb0e433547fdd Mon Sep 17 00:00:00 2001 From: Yifei SUN <100406743+miaomiao612@users.noreply.github.com> Date: Wed, 16 Nov 2022 03:41:33 +0800 Subject: [PATCH 20/33] Delete 1 --- site/data/1 | 1 - 1 file changed, 1 deletion(-) delete mode 100644 site/data/1 diff --git a/site/data/1 b/site/data/1 deleted file mode 100644 index 8b13789..0000000 --- a/site/data/1 +++ /dev/null @@ -1 +0,0 @@ - From c6ea3e0c7949f02c8d8892c9ce7c31ff56bfb3dc Mon Sep 17 00:00:00 2001 From: miaomiao612 Date: Wed, 16 Nov 2022 06:53:59 +0800 Subject: [PATCH 21/33] update --- site/js/map.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/site/js/map.js b/site/js/map.js index 01bb940..895a32b 100644 --- a/site/js/map.js +++ b/site/js/map.js @@ -2,7 +2,7 @@ * @Author: miaomiao612 dddoctorr612@gmail.com * @Date: 2022-11-11 03:00:55 * @LastEditors: miaomiao612 dddoctorr612@gmail.com - * @LastEditTime: 2022-11-16 02:51:23 + * @LastEditTime: 2022-11-16 06:49:21 * @FilePath: \voter-canvassing\site\js\map.js * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE */ @@ -76,10 +76,13 @@ function showVotersOnMap(votersToShow, voterMap) { }; voterMap.voterLayer = L.geoJSON(voterFeatureCollection, { pointToLayer: (feature, latlng) => L.circleMarker(latlng), - style: { - fillColor: '#83bf15', - fillOpacity: 0.3, - stroke: false, + style: { + fillColor: '#53C131', + fillOpacity: 0.5, + radius:6, + stroke: true, + weight:0.5, + color:'#000000', }, }).addTo(voterMap); } From 2a83dd3f0f32fe1f61a277606a2ab7c4dd790a43 Mon Sep 17 00:00:00 2001 From: Yifei SUN <100406743+miaomiao612@users.noreply.github.com> Date: Wed, 23 Nov 2022 17:39:29 -0500 Subject: [PATCH 22/33] Add files via upload --- index.html | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 index.html diff --git a/index.html b/index.html new file mode 100644 index 0000000..8982d1d --- /dev/null +++ b/index.html @@ -0,0 +1,65 @@ + + + + + + voter canvassing + + + + + + + + + + +
+ + + + List No. + + +
+
    +
    + Political Parties + + +
    +
    +
    +
    +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + \ No newline at end of file From 0cdac3c05865773af997f2d6ec715387a9c76162 Mon Sep 17 00:00:00 2001 From: Yifei SUN <100406743+miaomiao612@users.noreply.github.com> Date: Wed, 23 Nov 2022 17:39:47 -0500 Subject: [PATCH 23/33] Delete index.html --- index.html | 65 ------------------------------------------------------ 1 file changed, 65 deletions(-) delete mode 100644 index.html diff --git a/index.html b/index.html deleted file mode 100644 index 8982d1d..0000000 --- a/index.html +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - voter canvassing - - - - - - - - - - -
    - - - - List No. - - -
    -
      -
      - Political Parties - - -
      -
      -
      -
      -
      -
      -
      -
      -
      - - - - - - - - - - - - - - - - \ No newline at end of file From b98e71cfc1aea7217d4beaf0a5661861e77658d5 Mon Sep 17 00:00:00 2001 From: Yifei SUN <100406743+miaomiao612@users.noreply.github.com> Date: Wed, 23 Nov 2022 17:40:05 -0500 Subject: [PATCH 24/33] Add files via upload --- site/index.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/site/index.html b/site/index.html index 21e927c..8982d1d 100644 --- a/site/index.html +++ b/site/index.html @@ -30,7 +30,9 @@ List No. -
      +
      +
        +
        Political Parties From 1abf1da9b48195fb1ef0bcf6f9c5fb9ab94e0bca Mon Sep 17 00:00:00 2001 From: Yifei SUN <100406743+miaomiao612@users.noreply.github.com> Date: Wed, 23 Nov 2022 17:40:32 -0500 Subject: [PATCH 25/33] Add files via upload --- site/js/list.js | 40 +++++++++++++++++++++++++++++++++++++++ site/js/main.js | 33 +++++++++++++++++++++++++++++--- site/js/managedata.js | 2 -- site/js/map.js | 17 ++++++++++++++--- site/js/template-tools.js | 36 +++++++++++++++++++++++++++++++++++ 5 files changed, 120 insertions(+), 8 deletions(-) create mode 100644 site/js/list.js create mode 100644 site/js/template-tools.js diff --git a/site/js/list.js b/site/js/list.js new file mode 100644 index 0000000..469205d --- /dev/null +++ b/site/js/list.js @@ -0,0 +1,40 @@ +import{htmlToElement} from './template-tools.js'; + +function ShowVotersList(votersToShow,onFailure) { + + fetch(`./data/voters_lists/${votersToShow}.csv`) + .then(response => { + if (response.status === 200) { + const data = response.text(); + return data; + } else { + alert('Oh no, I failed to download the data.'); + if (onFailure) { onFailure() } + } + }) + .then(v => Papa.parse(v, { delimiter:"," })) + .catch(err => console.log(err)) + .then(result => { + let v = result.data.slice(1, result.data.length-1); + + //now we have many voters of certain list.no in a json format + for (const voter in result){ + const html = ` +
      • ${voter['name']} (id: ${voter['ID Number']})
      • + `; + const li = htmlToElement(html); + }//display voter's name and ID + } + ) + + + +} + + + + + +export{ + ShowVotersList, +}; \ No newline at end of file diff --git a/site/js/main.js b/site/js/main.js index fa56243..39e0bca 100644 --- a/site/js/main.js +++ b/site/js/main.js @@ -15,19 +15,46 @@ // individual component modules: // * [map.js]: for behavior related to the map -import { initMap, Search } from './map.js'; -//import { csvtojson } from './managedata.js'; +import { initMap, Search, updateUserPositionOn } from './map.js'; +import { ShowVotersList } from './list.js'; + let voterMap=initMap(); let votersToShow = document.querySelector('#listNo'); let search = document.querySelector('#search1'); + + + //let btn = document.getElementById("search1"); //btn.addEventListener("click", csvtojson(voterMap, votersToShow)); +// **Geolocation** -- `onUserPositionSuccess` will be called by the geolocation +// API if and when the user's position is successfully found. +function onUserPositionSuccess(pos) { + updateUserPositionOn(voterMap, pos); + } + +// **Geolocation** -- `onUserPositionSuccess` will be called by the geolocation +// API if and when there is an error in finding the user's position. + function onUserPositionFailure(err) { + console.log(err); + } + + +function setupGeolocationEvent() { + navigator.geolocation.getCurrentPosition( + onUserPositionSuccess, + onUserPositionFailure, + ); + } + Search(voterMap, search, votersToShow); +//setupGeolocationEvent(); +ShowVotersList(votersToShow); + + -Search(voterMap, search, votersToShow); window.voterMap=voterMap; window.votersToShow=votersToShow; diff --git a/site/js/managedata.js b/site/js/managedata.js index 34960a9..caf12f5 100644 --- a/site/js/managedata.js +++ b/site/js/managedata.js @@ -18,8 +18,6 @@ function csvtojson ( map, votersToShow, onFailure){ return v; }) - .then(result => showVotersOnMap( result, map)); - } diff --git a/site/js/map.js b/site/js/map.js index 895a32b..004c72c 100644 --- a/site/js/map.js +++ b/site/js/map.js @@ -42,7 +42,7 @@ function initMap() { return map; } -//convert json to a geojson-like feature +//convert a json to a geojson-like feature function makevoterFeature(voter) { return { @@ -72,7 +72,7 @@ function showVotersOnMap(votersToShow, voterMap) { const voterFeatureCollection = { "type": "FeatureCollection", - "features": votersToShow.map(makevoterFeature), + "features": votersToShow.map(makevoterFeature),//excuate one by one }; voterMap.voterLayer = L.geoJSON(voterFeatureCollection, { pointToLayer: (feature, latlng) => L.circleMarker(latlng), @@ -92,14 +92,25 @@ function showVotersOnMap(votersToShow, voterMap) { function Search (map, search, votersToShow) { search.addEventListener('click', () => { let votersToShow1 = votersToShow.value; - csvtojson(map, votersToShow1); + let result = csvtojson(map, votersToShow1); + showVotersOnMap(result, map); }); } +function updateUserPositionOn(map, pos) { + map.positionLayer.addData({ + 'type': 'Point', + 'coordinates': [pos.coords.longitude, pos.coords.latitude], + }); + map.setView([pos.coords.latitude, pos.coords.longitude], 18); + } + + export{ initMap, showVotersOnMap, Search, + updateUserPositionOn, }; diff --git a/site/js/template-tools.js b/site/js/template-tools.js new file mode 100644 index 0000000..b4e9248 --- /dev/null +++ b/site/js/template-tools.js @@ -0,0 +1,36 @@ +/* ==================== +The following two functions take a string of HTML and create DOM element objects +representing the tags, using the `template` feature of HTML. See the following +for more information: https://stackoverflow.com/a/35385518/123776 +==================== */ + +/* eslint-disable no-unused-vars */ + +/** + * @param {String} HTML representing a single element + * @return {Element} + */ + function htmlToElement(html) { + const template = document.createElement('template'); + const trimmedHtml = html.trim(); // Never return a text node of whitespace as the result + template.innerHTML = trimmedHtml; + return template.content.firstChild; + } + + /** + * @param {String} HTML representing any number of sibling elements + * @return {NodeList} + */ + function htmlToElements(html) { + const template = document.createElement('template'); + template.innerHTML = html; + return template.content.childNodes; + } + + window.htmlToElement = htmlToElement; + window.htmlToElements = htmlToElements; + + export { + htmlToElement, + htmlToElements, + }; \ No newline at end of file From 427167fcfe85e1f2c4c444817c59f08bfb6fed2a Mon Sep 17 00:00:00 2001 From: Yifei SUN <100406743+miaomiao612@users.noreply.github.com> Date: Wed, 23 Nov 2022 17:40:53 -0500 Subject: [PATCH 26/33] Add files via upload --- site/css/style.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site/css/style.css b/site/css/style.css index 698bf10..6998b56 100644 --- a/site/css/style.css +++ b/site/css/style.css @@ -48,7 +48,7 @@ opacity: 1; text-align: left; } - .v416_9 { + /*.list_container { width: 407px; height: 553px; background: rgba(152,152,152,1); @@ -57,7 +57,7 @@ top: 279px; left: 52px; overflow: hidden; - } + }*/ .v416_17 { width: 352px; height: 23px; From 7183bc73d0e7dc7d8c21cef5c54e9adbb402f34e Mon Sep 17 00:00:00 2001 From: Yifei SUN <100406743+miaomiao612@users.noreply.github.com> Date: Sat, 26 Nov 2022 17:47:48 -0500 Subject: [PATCH 27/33] Add files via upload --- list.js | 44 +++++++++++++++++ main.js | 61 +++++++++++++++++++++++ managedata.js | 30 ++++++++++++ map.js | 121 ++++++++++++++++++++++++++++++++++++++++++++++ papaparse.min.js | 7 +++ template-tools.js | 36 ++++++++++++++ 6 files changed, 299 insertions(+) create mode 100644 list.js create mode 100644 main.js create mode 100644 managedata.js create mode 100644 map.js create mode 100644 papaparse.min.js create mode 100644 template-tools.js diff --git a/list.js b/list.js new file mode 100644 index 0000000..f39e9ea --- /dev/null +++ b/list.js @@ -0,0 +1,44 @@ +import{htmlToElement} from './template-tools.js'; + +function ShowVotersList(votersToShow,onFailure) { + + fetch(`./data/voters_lists/${votersToShow}.csv`) + .then(response => { + if (response.status === 200) { + const data = response.text(); + return data; + } else { + alert('Oh no, I failed to download the data.'); + if (onFailure) { onFailure() } + } + }) + .then(v => Papa.parse(v, { delimiter:"," })) + .catch(err => console.log(err)) + .then(result => { + let v = result.data.slice(1, result.data.length-1); + return v; + + }) + + //now we have many voters of certain list.no in a json format + + .then(result =>{ + let D=result.map(showlist) + return D;} + ) +} + + //display voter's name and ID +function showlist(votersToShow) { + + const html = ` +
      • ${votersToShow['name']} (id: ${votersToShow['ID Number']})
      • + `; + + +} + + +export{ + ShowVotersList, +}; \ No newline at end of file diff --git a/main.js b/main.js new file mode 100644 index 0000000..9b52932 --- /dev/null +++ b/main.js @@ -0,0 +1,61 @@ +/* + * @Author: miaomiao612 dddoctorr612@gmail.com + * @Date: 2022-11-10 05:49:08 + * @LastEditors: miaomiao612 dddoctorr612@gmail.com + * @LastEditTime: 2022-11-16 02:55:08 + * @FilePath: \voter-canvassing\site\js\main.js + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ + +// voter canvassing App +// ============================ + +// The _main.js_ module defines the primary functionality of the app, and serves +// as the cross-component coordinator. Additional functionality is found in +// individual component modules: +// * [map.js]: for behavior related to the map + +import { initMap, Search, updateUserPositionOn } from './map.js'; +import { ShowVotersList } from './list.js'; + + + +let voterMap=initMap(); +let votersToShow = document.querySelector('#listNo'); +let search = document.querySelector('#search1'); +let List = document.querySelector("#voter-list"); + + +Search(voterMap, search, votersToShow); + + + +// **Geolocation** -- `onUserPositionSuccess` will be called by the geolocation +// API if and when the user's position is successfully found. +function onUserPositionSuccess(pos) { + updateUserPositionOn(voterMap, pos); + } + +// **Geolocation** -- `onUserPositionSuccess` will be called by the geolocation +// API if and when there is an error in finding the user's position. + function onUserPositionFailure(err) { + console.log(err); + } + + +//setupGeolocationEvent(); +function setupGeolocationEvent() { + navigator.geolocation.getCurrentPosition( + onUserPositionSuccess, + onUserPositionFailure, + ); + } +//setupGeolocationEvent(); +ShowVotersList(votersToShow); + + + + +window.voterMap=voterMap; +window.votersToShow=votersToShow; +window.search=search; diff --git a/managedata.js b/managedata.js new file mode 100644 index 0000000..2803a87 --- /dev/null +++ b/managedata.js @@ -0,0 +1,30 @@ +import { showVotersOnMap } from './map.js'; +//convert csv to json and display on map +function csvtojson ( map, votersToShow, onFailure){ + fetch(`./data/voters_lists/${votersToShow}.csv`) + + .then(response => { + if (response.status === 200) { + const data = response.text(); + return data; + } else { + alert('Oh no, I failed to download the data.'); + if (onFailure) { onFailure() } + } + }) + .then(v => Papa.parse(v, { delimiter:"," })) + .catch(err => console.log(err)) + .then(result => { + let v = result.data.slice(1, result.data.length-1); + return v; + }) + //now we get json version data of a certain listNO. + + .then(result => showVotersOnMap(result,map)) + + + } + +export{ + csvtojson, +}; \ No newline at end of file diff --git a/map.js b/map.js new file mode 100644 index 0000000..0b06582 --- /dev/null +++ b/map.js @@ -0,0 +1,121 @@ +/* + * @Author: miaomiao612 dddoctorr612@gmail.com + * @Date: 2022-11-11 03:00:55 + * @LastEditors: miaomiao612 dddoctorr612@gmail.com + * @LastEditTime: 2022-11-16 06:49:21 + * @FilePath: \voter-canvassing\site\js\map.js + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +import{ csvtojson } from './managedata.js'; +import{ ShowVotersList } from './list.js'; + +function onvoterClicked(evt) { + console.log(evt); + const voter = evt.layer.feature; + + const voterSelectedEvent = new CustomEvent('voter-selected', { detail: { voter } }); + window.dispatchEvent(voterSelectedEvent); +} + +function initMap() { + const map = L.map('voterMap', { maxZoom: 22, preferCanvas: true }).setView([39.95, -75.16], 13); + + const mapboxAccount = 'mapbox'; + const mapboxStyle = 'light-v10'; + const mapboxToken = 'pk.eyJ1IjoibWp1bWJlLXRlc3QiLCJhIjoiY2w3ZTh1NTIxMTgxNTQwcGhmODU2NW5kaSJ9.pBPd19nWO-Gt-vTf1pOHBA'; + L.tileLayer(`https://api.mapbox.com/styles/v1/${mapboxAccount}/${mapboxStyle}/tiles/256/{z}/{x}/{y}@2x?access_token=${mapboxToken}`, { + maxZoom: 19, + attribution: '© Mapbox © OpenStreetMap Improve this map', + }).addTo(map); + map.treeLayer = L.geoJSON(null, { + pointToLayer: (feature, latlng) => L.circleMarker(latlng), + style: { + fillColor: '#83bf15', + fillOpacity: 0.3, + stroke: false, + }, + }).addTo(map); + + map.treeLayer.addEventListener('click', onvoterClicked); + + map.positionLayer = L.geoJSON(null).addTo(map); + + return map; +} + +//convert a json to a geojson-like feature +function makevoterFeature(voter) +{ + return { + "type": "Feature", + "id": voter['ID Number'], + "properties": { + "Last Name":voter['Last Name'], + "First Name": voter['First Name'], + "Registration Date": voter['Registration Date'], + "Voter Status": voter['Voter Status'], + "Party Code": voter['Party Code'], + + }, + "geometry": + { "type": "Point", + "coordinates":[voter['28'].substr(0, 18), voter['28'].substr(19, voter.length)], + + }, + }; +} + +//Use the function to display the voters' location on the map. +function showVotersOnMap(votersToShow_json, voterMap) { + if (voterMap.voterLayer !== undefined){ + voterMap.removeLayer(voterMap.voterLayer); + } + + const voterFeatureCollection = { + "type": "FeatureCollection", + "features": votersToShow_json.map(makevoterFeature),//excuate one by one, convert json like data to geojson like feature + + }; + + + voterMap.voterLayer = L.geoJSON(voterFeatureCollection, { + pointToLayer: (feature, latlng) => L.circleMarker(latlng), + style: { + fillColor: '#53C131', + fillOpacity: 0.5, + radius:6, + stroke: true, + weight:0.5, + color:'#000000', + }, + }).addTo(voterMap); + } + + +//use this function to search the voters by listNo +function Search (map, search, votersToShow) { + search.addEventListener('click', () => { + let votersToShow1 = votersToShow.value; + csvtojson(map, votersToShow1); + ShowVotersList(votersToShow1); + + }); + +} + +function updateUserPositionOn(map, pos) { + map.positionLayer.addData({ + 'type': 'Point', + 'coordinates': [pos.coords.longitude, pos.coords.latitude], + }); + map.setView([pos.coords.latitude, pos.coords.longitude], 18); + } + + +export{ + initMap, + showVotersOnMap, + Search, + updateUserPositionOn, + +}; diff --git a/papaparse.min.js b/papaparse.min.js new file mode 100644 index 0000000..14c98ff --- /dev/null +++ b/papaparse.min.js @@ -0,0 +1,7 @@ +/* @license +Papa Parse +v5.0.2 +https://github.com/mholt/PapaParse +License: MIT +*/ +!function(e,t){"function"==typeof define&&define.amd?define([],t):"object"==typeof module&&"undefined"!=typeof exports?module.exports=t():e.Papa=t()}(this,function s(){"use strict";var f="undefined"!=typeof self?self:"undefined"!=typeof window?window:void 0!==f?f:{};var n=!f.document&&!!f.postMessage,o=n&&/blob:/i.test((f.location||{}).protocol),a={},h=0,b={parse:function(e,t){var r=(t=t||{}).dynamicTyping||!1;q(r)&&(t.dynamicTypingFunction=r,r={});if(t.dynamicTyping=r,t.transform=!!q(t.transform)&&t.transform,t.worker&&b.WORKERS_SUPPORTED){var i=function(){if(!b.WORKERS_SUPPORTED)return!1;var e=(r=f.URL||f.webkitURL||null,i=s.toString(),b.BLOB_URL||(b.BLOB_URL=r.createObjectURL(new Blob(["(",i,")();"],{type:"text/javascript"})))),t=new f.Worker(e);var r,i;return t.onmessage=_,t.id=h++,a[t.id]=t}();return i.userStep=t.step,i.userChunk=t.chunk,i.userComplete=t.complete,i.userError=t.error,t.step=q(t.step),t.chunk=q(t.chunk),t.complete=q(t.complete),t.error=q(t.error),delete t.worker,void i.postMessage({input:e,config:t,workerId:i.id})}var n=null;b.NODE_STREAM_INPUT,"string"==typeof e?n=t.download?new l(t):new p(t):!0===e.readable&&q(e.read)&&q(e.on)?n=new m(t):(f.File&&e instanceof File||e instanceof Object)&&(n=new c(t));return n.stream(e)},unparse:function(e,t){var i=!1,_=!0,g=",",v="\r\n",n='"',s=n+n,r=!1,a=null;!function(){if("object"!=typeof t)return;"string"!=typeof t.delimiter||b.BAD_DELIMITERS.filter(function(e){return-1!==t.delimiter.indexOf(e)}).length||(g=t.delimiter);("boolean"==typeof t.quotes||Array.isArray(t.quotes))&&(i=t.quotes);"boolean"!=typeof t.skipEmptyLines&&"string"!=typeof t.skipEmptyLines||(r=t.skipEmptyLines);"string"==typeof t.newline&&(v=t.newline);"string"==typeof t.quoteChar&&(n=t.quoteChar);"boolean"==typeof t.header&&(_=t.header);if(Array.isArray(t.columns)){if(0===t.columns.length)throw new Error("Option columns is empty");a=t.columns}void 0!==t.escapeChar&&(s=t.escapeChar+n)}();var o=new RegExp(U(n),"g");"string"==typeof e&&(e=JSON.parse(e));if(Array.isArray(e)){if(!e.length||Array.isArray(e[0]))return u(null,e,r);if("object"==typeof e[0])return u(a||h(e[0]),e,r)}else if("object"==typeof e)return"string"==typeof e.data&&(e.data=JSON.parse(e.data)),Array.isArray(e.data)&&(e.fields||(e.fields=e.meta&&e.meta.fields),e.fields||(e.fields=Array.isArray(e.data[0])?e.fields:h(e.data[0])),Array.isArray(e.data[0])||"object"==typeof e.data[0]||(e.data=[e.data])),u(e.fields||[],e.data||[],r);throw new Error("Unable to serialize unrecognized input");function h(e){if("object"!=typeof e)return[];var t=[];for(var r in e)t.push(r);return t}function u(e,t,r){var i="";"string"==typeof e&&(e=JSON.parse(e)),"string"==typeof t&&(t=JSON.parse(t));var n=Array.isArray(e)&&0=this._config.preview;if(o)f.postMessage({results:n,workerId:b.WORKER_ID,finished:a});else if(q(this._config.chunk)&&!t){if(this._config.chunk(n,this._handle),this._handle.paused()||this._handle.aborted())return void(this._halted=!0);n=void 0,this._completeResults=void 0}return this._config.step||this._config.chunk||(this._completeResults.data=this._completeResults.data.concat(n.data),this._completeResults.errors=this._completeResults.errors.concat(n.errors),this._completeResults.meta=n.meta),this._completed||!a||!q(this._config.complete)||n&&n.meta.aborted||(this._config.complete(this._completeResults,this._input),this._completed=!0),a||n&&n.meta.paused||this._nextChunk(),n}this._halted=!0},this._sendError=function(e){q(this._config.error)?this._config.error(e):o&&this._config.error&&f.postMessage({workerId:b.WORKER_ID,error:e,finished:!1})}}function l(e){var i;(e=e||{}).chunkSize||(e.chunkSize=b.RemoteChunkSize),u.call(this,e),this._nextChunk=n?function(){this._readChunk(),this._chunkLoaded()}:function(){this._readChunk()},this.stream=function(e){this._input=e,this._nextChunk()},this._readChunk=function(){if(this._finished)this._chunkLoaded();else{if(i=new XMLHttpRequest,this._config.withCredentials&&(i.withCredentials=this._config.withCredentials),n||(i.onload=y(this._chunkLoaded,this),i.onerror=y(this._chunkError,this)),i.open("GET",this._input,!n),this._config.downloadRequestHeaders){var e=this._config.downloadRequestHeaders;for(var t in e)i.setRequestHeader(t,e[t])}if(this._config.chunkSize){var r=this._start+this._config.chunkSize-1;i.setRequestHeader("Range","bytes="+this._start+"-"+r)}try{i.send()}catch(e){this._chunkError(e.message)}n&&0===i.status?this._chunkError():this._start+=this._config.chunkSize}},this._chunkLoaded=function(){4===i.readyState&&(i.status<200||400<=i.status?this._chunkError():(this._finished=!this._config.chunkSize||this._start>function(e){var t=e.getResponseHeader("Content-Range");if(null===t)return-1;return parseInt(t.substr(t.lastIndexOf("/")+1))}(i),this.parseChunk(i.responseText)))},this._chunkError=function(e){var t=i.statusText||e;this._sendError(new Error(t))}}function c(e){var i,n;(e=e||{}).chunkSize||(e.chunkSize=b.LocalChunkSize),u.call(this,e);var s="undefined"!=typeof FileReader;this.stream=function(e){this._input=e,n=e.slice||e.webkitSlice||e.mozSlice,s?((i=new FileReader).onload=y(this._chunkLoaded,this),i.onerror=y(this._chunkError,this)):i=new FileReaderSync,this._nextChunk()},this._nextChunk=function(){this._finished||this._config.preview&&!(this._rowCount=this._input.size,this.parseChunk(e.target.result)},this._chunkError=function(){this._sendError(i.error)}}function p(e){var r;u.call(this,e=e||{}),this.stream=function(e){return r=e,this._nextChunk()},this._nextChunk=function(){if(!this._finished){var e=this._config.chunkSize,t=e?r.substr(0,e):r;return r=e?r.substr(e):"",this._finished=!r,this.parseChunk(t)}}}function m(e){u.call(this,e=e||{});var t=[],r=!0,i=!1;this.pause=function(){u.prototype.pause.apply(this,arguments),this._input.pause()},this.resume=function(){u.prototype.resume.apply(this,arguments),this._input.resume()},this.stream=function(e){this._input=e,this._input.on("data",this._streamData),this._input.on("end",this._streamEnd),this._input.on("error",this._streamError)},this._checkIsFinished=function(){i&&1===t.length&&(this._finished=!0)},this._nextChunk=function(){this._checkIsFinished(),t.length?this.parseChunk(t.shift()):r=!0},this._streamData=y(function(e){try{t.push("string"==typeof e?e:e.toString(this._config.encoding)),r&&(r=!1,this._checkIsFinished(),this.parseChunk(t.shift()))}catch(e){this._streamError(e)}},this),this._streamError=y(function(e){this._streamCleanUp(),this._sendError(e)},this),this._streamEnd=y(function(){this._streamCleanUp(),i=!0,this._streamData("")},this),this._streamCleanUp=y(function(){this._input.removeListener("data",this._streamData),this._input.removeListener("end",this._streamEnd),this._input.removeListener("error",this._streamError)},this)}function r(g){var a,o,h,i=Math.pow(2,53),n=-i,s=/^\s*-?(\d*\.?\d+|\d+\.?\d*)(e[-+]?\d+)?\s*$/i,u=/(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))/,t=this,r=0,f=0,d=!1,e=!1,l=[],c={data:[],errors:[],meta:{}};if(q(g.step)){var p=g.step;g.step=function(e){if(c=e,_())m();else{if(m(),0===c.data.length)return;r+=e.data.length,g.preview&&r>g.preview?o.abort():p(c,t)}}}function v(e){return"greedy"===g.skipEmptyLines?""===e.join("").trim():1===e.length&&0===e[0].length}function m(){if(c&&h&&(k("Delimiter","UndetectableDelimiter","Unable to auto-detect delimiting character; defaulted to '"+b.DefaultDelimiter+"'"),h=!1),g.skipEmptyLines)for(var e=0;e=l.length?"__parsed_extra":l[r]),g.transform&&(s=g.transform(s,n)),s=y(n,s),"__parsed_extra"===n?(i[n]=i[n]||[],i[n].push(s)):i[n]=s}return g.header&&(r>l.length?k("FieldMismatch","TooManyFields","Too many fields: expected "+l.length+" fields but parsed "+r,f+t):r=i.length/2?"\r\n":"\r"}(e,i)),h=!1,g.delimiter)q(g.delimiter)&&(g.delimiter=g.delimiter(e),c.meta.delimiter=g.delimiter);else{var n=function(e,t,r,i,n){var s,a,o,h;n=n||[",","\t","|",";",b.RECORD_SEP,b.UNIT_SEP];for(var u=0;u=L)return R(!0)}else for(g=M,M++;;){if(-1===(g=a.indexOf(O,g+1)))return t||u.push({type:"Quotes",code:"MissingQuotes",message:"Quoted field unterminated",row:h.length,index:M}),w();if(g===i-1)return w(a.substring(M,g).replace(_,O));if(O!==z||a[g+1]!==z){if(O===z||0===g||a[g-1]!==z){var y=E(-1===m?p:Math.min(p,m));if(a[g+1+y]===D){f.push(a.substring(M,g).replace(_,O)),a[M=g+1+y+e]!==O&&(g=a.indexOf(O,M)),p=a.indexOf(D,M),m=a.indexOf(I,M);break}var k=E(m);if(a.substr(g+1+k,n)===I){if(f.push(a.substring(M,g).replace(_,O)),C(g+1+k+n),p=a.indexOf(D,M),g=a.indexOf(O,M),o&&(S(),j))return R();if(L&&h.length>=L)return R(!0);break}u.push({type:"Quotes",code:"InvalidQuotes",message:"Trailing quote on quoted field is malformed",row:h.length,index:M}),g++}}else g++}return w();function b(e){h.push(e),d=M}function E(e){var t=0;if(-1!==e){var r=a.substring(g+1,e);r&&""===r.trim()&&(t=r.length)}return t}function w(e){return t||(void 0===e&&(e=a.substr(M)),f.push(e),M=i,b(f),o&&S()),R()}function C(e){M=e,b(f),f=[],m=a.indexOf(I,M)}function R(e,t){return{data:t||!1?h[0]:h,errors:u,meta:{delimiter:D,linebreak:I,aborted:j,truncated:!!e,cursor:d+(r||0)}}}function S(){A(R(void 0,!0)),h=[],u=[]}function x(e,t,r){var i={nextDelim:void 0,quoteSearch:void 0},n=a.indexOf(O,t+1);if(t Date: Sun, 27 Nov 2022 16:34:28 -0500 Subject: [PATCH 28/33] Create election_lookup.json --- site/data/election_lookup.json | 162 +++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 site/data/election_lookup.json diff --git a/site/data/election_lookup.json b/site/data/election_lookup.json new file mode 100644 index 0000000..4dccefa --- /dev/null +++ b/site/data/election_lookup.json @@ -0,0 +1,162 @@ +{ + "Election 1": { + "description": "2020 GENERAL PRIMARY", + "date": "06/02/2020" + }, + "Election 2": { + "description": "2021 MUNICIPAL ELECTION", + "date": "11/02/2021" + }, + "Election 3": { + "description": "2020 GENERAL ELECTION", + "date": "11/03/2020" + }, + "Election 4": { + "description": "2017 MUNICIPAL PRIMARY", + "date": "05/16/2017" + }, + "Election 5": { + "description": "2017 MUNICIPAL ELECTION", + "date": "11/07/2017" + }, + "Election 6": { + "description": "2018 GENERAL ELECTION", + "date": "11/06/2018" + }, + "Election 7": { + "description": "2018 GENERAL PRIMARY", + "date": "05/15/2018" + }, + "Election 8": { + "description": "2019 MUNICIPAL PRIMARY", + "date": "05/21/2019" + }, + "Election 9": { + "description": "2019 Special Election 190TH Leg", + "date": "03/12/2019" + }, + "Election 10": { + "description": "2020 SPECIAL ELECTION 190TH DIST", + "date": "02/25/2020" + }, + "Election 11": { + "description": "2021 MUNICIPAL PRIMARY", + "date": "05/18/2021" + }, + "Election 12": { + "description": "2019 MUNICIPAL ELECTION", + "date": "11/05/2019" + }, + "Election 13": { + "description": "2022 GENERAL PRIMARY", + "date": "05/17/2022" + }, + "Election 14": { + "description": "2006 GENERAL PRIMARY", + "date": "05/16/2006" + }, + "Election 15": { + "description": "2006 GENERAL ELECTION", + "date": "11/07/2006" + }, + "Election 16": { + "description": "2007 GENERAL PRIMARY", + "date": "05/15/2007" + }, + "Election 17": { + "description": "2007 GENERAL ELECTION", + "date": "11/06/2007" + }, + "Election 18": { + "description": "2008 GENERAL PRIMARY", + "date": "04/22/2008" + }, + "Election 19": { + "description": "2008 GENERAL ELECTION", + "date": "11/04/2008" + }, + "Election 20": { + "description": "2009 MUNICIPAL PRIMARY ELECTION", + "date": "05/19/2009" + }, + "Election 21": { + "description": "2009 MUNICIPAL GENERAL ELECTION", + "date": "11/03/2009" + }, + "Election 22": { + "description": "2010 GENERAL PRIMARY", + "date": "05/18/2010" + }, + "Election 23": { + "description": "2010 GENERAL ELECTION", + "date": "11/02/2010" + }, + "Election 24": { + "description": "2011 SPECIAL ELECTION", + "date": "02/01/2011" + }, + "Election 25": { + "description": "2011 MUNICIPAL PRIMARY", + "date": "05/17/2011" + }, + "Election 26": { + "description": "2011 MUNICIPAL ELECTION", + "date": "11/08/2011" + }, + "Election 27": { + "description": "2012 GENERAL PRIMARY", + "date": "04/24/2012" + }, + "Election 28": { + "description": "2012 GENERAL ELECTION", + "date": "11/06/2012" + }, + "Election 29": { + "description": "2013 MUNICIPAL PRIMARY", + "date": "05/21/2013" + }, + "Election 30": { + "description": "2013 MUNICIPAL ELECTION", + "date": "11/05/2013" + }, + "Election 31": { + "description": "2014 GENERAL PRIMARY", + "date": "05/20/2014" + }, + "Election 32": { + "description": "2014 GENERAL ELECTION", + "date": "11/04/2014" + }, + "Election 33": { + "description": "Special Election for the170thLegislative District", + "date": "03/24/2015" + }, + "Election 34": { + "description": "2015 MUNICIPAL PRIMARY", + "date": "05/19/2015" + }, + "Election 35": { + "description": "2015 SPECIAL ELECTION FOR THE 174TH,191ST,195TH, L", + "date": "08/11/2015" + }, + "Election 36": { + "description": "2015 MUNICIPAL ELECTION", + "date": "11/03/2015" + }, + "Election 37": { + "description": "2016 SPECIAL ELECTION (03/15/2016)", + "date": "03/15/2016" + }, + "Election 38": { + "description": "2016 GENERAL PRIMARY", + "date": "04/26/2016" + }, + "Election 39": { + "description": "2016 GENERAL ELECTION", + "date": "11/08/2016" + }, + "Election 40": { + "description": "2017 SPECIAL ELECTION LEGISLATIVE DISTRICT 197", + "date": "03/21/2017" + } +} From 5989db7e4955868489625c562b7954eadc59532a Mon Sep 17 00:00:00 2001 From: Yifei SUN <100406743+miaomiao612@users.noreply.github.com> Date: Sun, 27 Nov 2022 16:34:58 -0500 Subject: [PATCH 29/33] Create political_party_lookup.json --- site/data/political_party_lookup.json | 535 ++++++++++++++++++++++++++ 1 file changed, 535 insertions(+) create mode 100644 site/data/political_party_lookup.json diff --git a/site/data/political_party_lookup.json b/site/data/political_party_lookup.json new file mode 100644 index 0000000..62408ea --- /dev/null +++ b/site/data/political_party_lookup.json @@ -0,0 +1,535 @@ +{ + "3RD": "3rd", + "A": "ALL", + "ABO": "ABOLITIONIST", + "AC": "ANARCHIST", + "ACO": "ANARCHO-COMMUNIST", + "ACP": "ANARCHO CAPITALIST", + "ACR": "ALL CROOKS", + "AD": "ADARIAN", + "AE": "AMERICAN EAGLE", + "AF": "AMERICAN FIRST PARTY", + "AFP": "AMERICAN FREEDOM PARTY", + "AG": "ALMIGHTY GOD'S", + "AH": "AMERICAN HERITAGE", + "AI": "AMERICAN INDEPENDENT", + "AIP": "AIP", + "AL": "AMERICAN LABOR", + "AMA": "AMERICA", + "ALL": "ALLAH", + "AM": "AMERICAN", + "AMD": "AMERICAN DELTA", + "AME": "AMERICA'S", + "AMF": "AMERICA FIRST", + "AMI": "AMERICAN INDIAN", + "AMRE": "American Reform", + "AMRL": "AMERICAL LIBERTY", + "AN": "AMERICAN NAZI", + "ANA": "ANARCHY", + "ANL": "ANIMAL LIFE", + "ANO": "ANONYMOUS", + "ANP": "AIN'T NO PARTY LIKE A POLITICAL PARTY", + "ANY": "ANY", + "AO": "ANTI OBAMA", + "AP": "AMERICAN PATRIOT", + "APJ": "APPLE JUICE", + "APP": "AMERICA'S PARTY PENNSYLVANIA", + "APR": "AMERICAN FIRST PROGRESSIVE", + "APTY": "AMERICA's PARTY ", + "ARI": "ARISTOCRAT", + "ARP": "AMERICAN REVOLUTIONARY PARTY", + "ASF": "AMERICA - SEMPER FI", + "ASI": "ASIAN", + "ASM": "ASSEMBLY", + "ASP": "American Solidarity Party", + "AT": "ATHEIST", + "ATP": "AMERICAN TEA PARTY", + "AU": "AMERICAN UNITY", + "AW": "AWAKE", + "AZ": "AQUAZIAN ZIONIST", + "AZPA": "AQUARIAN ZIONIST PARTY OF AMERICA", + "AYE": "Aseyev", + "B": "BIRTHDAY", + "BA": "BLUE ARMY", + "BH": "BOTH", + "BL": "BLISS", + "BLP": "BLACK PANTHER", + "BM": "BULL MOOSE", + "BMP": "BOTH MAJOR PARTIES", + "BO": "BARACK OBAMA", + "BP": "BI-PARTISAN", + "BPAT": "BEST PERSON AT THE TIME", + "BPFJ": "BEST PERSON FOR THE JOB", + "BS": "BERNIE SANDERS", + "BSRR": "BEER/SEX/ROCK ROLL", + "BSTP": "BEST PERSON", + "BTH": "BOTH 1/2", + "BTM": "BETWEEN MIDDLE", + "C": "CONSERVATIVE", + "CA": "CAPITALIST", + "CB": "CAMPBELL PARTY", + "CC": "CHRISTIAN CONSERVATIVE", + "CCO": "CHRISTIAN COALITION", + "CCUS": "CATHOLIC CENTER PARTY USA", + "CD": "CHRISTIAN DEMOCRAT", + "CDU": "CHRISTIAN DEMOCRATIC PARTY U.S.A.", + "CDUN": "CHRISTIAN DEMOCRAT UNION", + "CE": "CENTRALIST", + "CF": "CONFEDERATE", + "CFED": "Constitutional Federalist", + "CH": "CHRISTIAN", + "CHA": "Chablais", + "CHG": "CHANGE", + "CHY": "Christianity", + "CL": "CONSTITUTIONAL", + "CLI": "CHARLIE", + "CLL": "CHRISTIANS FOR LIFE AND LIBERTY", + "CM": "COMMUNIST", + "CMR": "COMMERCIAL", + "CN": "CONFIDENSIAL", + "CNC": "CONSTITUTIONAL CONSERVATIVE", + "CNT": "CENTRIST", + "CNLB": "CENTRIST LIBERTARIAN", + "CO": "CONSUMER'S", + "COD": "CONSERVATIVE DEMOCRAT", + "COI": "CONSERVATIVE INDEPENDENT", + "COL": "COLL", + "COM": "COMMUNIST PARTY USA", + "CON": "CONSUMER", + "CP": "CITIZEN'S", + "CPU": "CPUSA", + "CR": "Conservative Republican", + "CRE": "CARE", + "CRT": "CIVIL RIGHTS", + "CS": "Common Sense", + "CSI": "COMMON SENSE INDEPENDENT", + "CSIP": "CSI PARTY", + "CT": "CONSTITUTION", + "CTL": "Cocktail Party", + "CTT": "CONSTITUTIONALIST", + "D": "DEMOCRATIC", + "DEAB": "Democrats Abroad", + "DEC": "DECEPTICON", + "DEM": "_DEMOCRACY", + "DEP": "DEPPERT", + "DIE": "DIETZIST", + "DIS": "DISABILITY", + "DKY": "DONT KNOW YET", + "DL": "DEMOCRATIC LIBERAL", + "DNA": "Democratic-Non Affiliation", + "DNV": "DO NOT VOTE", + "DPD": "DEPENDED", + "DPN": "DEPENDS", + "DPP": "DEMOCRATIC PROGRESSIVE PARTY", + "DR": "Democratic Republican", + "DS": "DEMOCRATIC SOCIALIST", + "DSN": "DEAD SOON", + "DSNY": "Disney Party", + "DST": "DMCRT SOCIALIST", + "DT": "DON\u2019T KNOW", + "DTP": "DIESEL TRUCK PARTY", + "DTS": "DECLINE TO STATE", + "E": "EVERYDAY", + "ECO": "Ecomagen", + "ECS": "Economic Statism", + "EGA": "Egalitare", + "EMET": "EMET", + "ENP": "EGYPTIAN", + "EPTY": "Ethan's Party", + "EQU": "EQuAliST", + "EX": "EXPERT", + "FA": "FASCIST", + "FAC": "FACIST", + "FAS": "FASCIM", + "FD": "FREEDOM", + "FE": "FEDERALIST", + "FLT": "Free\\Libert\u00e8", + "FM": "FEMINIST MAJORITY", + "FO": "FUGIFINO", + "FP": "FREAK POWER", + "FR": "FREE", + "FRA": "FREE AGENT", + "FRUSA": "FREEDOM USA", + "FS": "FREEDOM SELF", + "FT": "FREETHINKER", + "FTP": "FOR THE PEOPLE", + "FUT": "FUCK TRUP", + "G": "GOD", + "GAD": "GUNS AND DOPE", + "GD": "GREEN DEMOCRAT", + "GDI": "GDI", + "GE": "GALACTIC EMPIRE", + "GG": "GOLD GOOSE", + "GIM": "GIANT METEOR", + "GJ": "GARY JOHNSON", + "GM": "GRAND METACOSMOS", + "GN": "GOOD NEIGHBOR", + "GO": "GOOD ONE", + "GOP": "GOP", + "GP": "GREEN PARTY", + "GPUS": "GREEN PARTY OF THE US", + "GR": "GREEN", + "GRD": "GREEN DEMOCRATIC", + "GRNI": "GREEN INDEPENDENT", + "GRR": "GRASS ROOT", + "GS": "GO STEELERS", + "GT": "Go Trump", + "GTP": "GREEN TEA PARTY", + "GW": "George Washington", + "H": "HALLOWEEN", + "HAB": "HABIBI", + "HAP": "HAPPY", + "HC": "HILLERY CLINTON", + "HE": "HELLO", + "HI": "HUMAN INTEREST", + "HIL": "HILLARY", + "HILA": "HILARY", + "HO": "HORDE", + "HOG": "HOG4BOSS", + "HP": "Hoffman Party", + "HR": "HUMAN RACE", + "HSP": "HOLY SPIRIT", + "HTL": "HITLER", + "HUM": "HUMANITARIAN", + "HUP": "HUMANE", + "I": "INDEPENDENT", + "IA": "INDEPENDENCE PARTY OF AMERICA", + "IAPP": "INDEPENDENT AMERICAN PARTY OF PA", + "IC": "INDEPENDENT-COMPLETION", + "ICC": "Independent Constitutional Conservative", + "ICL": "INDEPENDENT CONSERVATIVE LIBERTARIAN", + "ICO": "INDEPENDENT CONSERVATIVE", + "ICON": "INDEPENDENT CONSTITUTIONALIST", + "ID": "INDEPENDENT DEMOCRAT", + "INDd": "IND.", + "INT": "INTRA", + "INTE": "INTELLIGENT", + "IDK": "I DON'T KNOW", + "IDL": "IDOL", + "IDR": "I DONT REGISTER ", + "IG": "INDEPENDENT GREEN", + "IITM": "I'M IN THE MIDDLE", + "IK": "IDK", + "IL": "INDEPENDENT/LIBERTARIAN", + "ILM": "ILLUMINATI", + "IM": "INDEPENDENT MODERATE", + "IN": "INTERESTING", + "IND": "INDEPENDENCE", + "INDE": "INDEPENDANT", + "INDY": "INDY", + "INRE": "INDEPENDANT/REPUBLIC", + "INNA": "Independent No Affiliation ", + "INNP": "INDEPENDENT/NO PARTY", + "IP": "INDEPENDENT POPULIST", + "IPPA": "IPPA", + "IR": "INDEPENDENT REPUBLICAN", + "IS": "INTERNATIONAL SOCIALIST", + "IT": "INDEPENT", + "ITENT": "INDEPENTENT", + "ITM": "Intermediated", + "IV": "INDIVIDUAL", + "IVFABP": "I VOTE FOR A BETTER PERSON NOT", + "JBN": "JACOBIN", + "J": "JUBILEEIAN", + "JD": "JEDI", + "JO": "JACKASS-ONE", + "JON": "JOHNSON'S", + "JP": "JUSTICE PARTY", + "JS": "JESUS", + "KEG": "KEG", + "KN": "KNOW NOTHING", + "KNP": "KUNNERMAN", + "KOG": "KINGDOM OF GOD", + "KQ": "KINGS & QUEENS", + "KWAD": "KWAD", + "L": "LABOR", + "LA": "LABORER", + "LAN": "LANNISTER", + "LAT": "LATINA", + "LD": "Liberal Democrat", + "LEG": "LEGALIST", + "LF": "LAISSE-FAIRE CAPITALIST", + "LG": "LIBERAL GREENE", + "LI": "LIBERAL", + "LIB": "Liberalist", + "LIBIN": "LIBERAL/INDEPENDENT", + "LIUP": "Liberty Union Party", + "LN": "LIBERTARIAN", + "LNS": "LIBERTARIAN SOCIALIST", + "LNSG": "LIBERTARIAN NATIONAL SOCIALIST GREEN", + "LR": "LIBERTARIAN REPUBLICAN", + "LREP": "LIBERAL REPUBLICAN", + "LT": "LIBERTARIAN TRANSHUMANIST", + "LUK": "LUKAWANDA", + "M": "MODERATE", + "MA": "MAITER", + "MAJA": "MARIJUANA", + "MAN": "MAN", + "MARR": "Marriage", + "MAY": "MAYBE", + "MAS": "MIGHT AS WELL", + "MC": "McCain", + "MCHAR": "MORAL CHARACTER", + "MDWP": "MODERATE WARD PARTY", + "MG": "MIDDLE GROUND", + "MI": "MANAYUNK INDEPENDENT", + "MID": "MIDDLE", + "MIG": "MARK IS GOD", + "MIN": "MODERATE \\ INDEPENDENT", + "ML": "MODERATE-LIBERAL", + "MM": "MICKEY MOUSE", + "MMI": "ME MYSELF AND I", + "MNT": "MONARCHIST", + "MODR": "MODERN REPUBLICAN", + "MP": "Moderate Republican", + "MOP": "Movement for a People's Party Or None", + "MRP": "Marijuana Reform Party", + "MRT": "MR TRUMP", + "MSE": "MEASE", + "MU": "MUTUAL", + "MUS": "MUSLIM", + "MW": "MODERN WHIG", + "MWP": "MODERN WHIG PARTY", + "MX": "MARXIST PARTY", + "MYMED": "MEN YOGA MEDITATION", + "MYP": "My Party", + "MZ": "MADI Z", + "N": "N/A", + "NA": "NEW ALLIANCE", + "NAI": "NEW AFRIKAN INDEPENDENCE", + "NAT": "NAT'L TAXPAYER", + "NC": "NON-COMMITTAL", + "NCP": "NON-CONFORMIST PARTY", + "ND": "NOT DEMO-REPO", + "NE": "NEUTRAL", + "NEI": "Not Either", + "NEO": "NEO-AGRARIAN", + "NF": "NO AFFILIATION", + "NI": "NOT INTERESTED", + "NINC": "NON-INCRIMINATING", + "NL": "NATURAL LAW", + "NO": "NO PARTY", + "NODE": "NON DENOMINATIONAL", + "NON": "NONE", + "NOYO": "None-Your", + "NOO": "NO", + "NOP": "NON-PARTISAN", + "NOPA": "NO PARTY AFFILIATION", + "NOS": "Non Specific", + "NOT": "NOTALITARIAN", + "NOV": "NOVELIST", + "NOW": "NO WAY", + "NP": "NEW PATRIOT", + "NPA": "Non Party", + "NPF": "No Preference", + "NPP": "NEW PATRIOT PARTY", + "NPRO": "NEW PROGRESSIVE", + "NPS": "NPS", + "NRA": "NRA", + "NS": "NATIONAL SOCIALIST", + "NSAL": "NSALP", + "NSSLP": "THE NATIONAL SOCIALIST SONS OF LIBERTY PARTY", + "NST": "NATIONALIST", + "NT": "NATIONAL TAXPAYERS", + "NTRP": "NOT TRUMP", + "NTS": "NOT SURE", + "NU": "NO LONGER IN USE", + "NVTR": "#NeverTrump", + "NW": "NEOWHIG", + "NZ": "NAZI", + "NYP": "NOT YOU PROBLEM", + "O": "OPRAH", + "OBA": "OBAMA", + "OLAP": "Ol' American Party", + "OP": "OPEN", + "OPV": "OTHER POLITICAL VIEWS", + "OR": "ORANGE", + "OTH": "OTHER", + "OW": "OLD WHIG", + "OWN": "OWN", + "OWW": "Old wagon Wheel", + "P": "PUMPKIN", + "P2": "PP", + "PA": "PA FOR PEROT", + "PA2": "PA", + "PAL": "Pacifist/Libertarian", + "PAP": "PEACE & PROSPERITY", + "PAR": "PARTY FOR SOCIALISM AND LIBERIA", + "PART": "PARTY", + "PAS": "PENNSYLVANIA SOVEREIGNS", + "PAST": "PASTAFARIEN", + "PE": "PEDESTRIAN", + "PENN": "PENNSYLVANIA", + "PEPA": "PEACE PARTY", + "PER": "PERSONAL", + "PF": "PEACE AND FREEDOM", + "PFP": "#66 PA FOR PEROT", + "PG": "PACIFIC GREEN", + "PH": "PROHIBITION", + "PHA": "PHILOSOPHICAL ANARCHIST", + "PI": "PENNSYLVANIA INDEPENDENT PARTY", + "PIR": "PIRATE", + "PIZ": "PIZZA PARTY", + "PJ": "THE PARTY OF JAY", + "PL": "PRO-LIFE", + "PLL": "Pleasant Living", + "PNP": "Pennsylvania Nationalist Party ", + "PNT": "PANTS PARTY", + "PNTS": "PREFER NOT TO SAY", + "PO": "POPULIST", + "POL": "POLITICAL", + "POLA": "POLITICAL ATHEIST", + "POO": "PARTY OF ONE", + "PP": "PATRIOT", + "PPD": "PPD", + "PPOA": "Progressive Party of America", + "PPP": "PANSEXUAL PEACE PARTY", + "PPUS": "PIRATE PARTY OF THE UNITED STATES", + "PR": "PROGRESSIVE", + "PRE": "PRESIDENT", + "PRI": "PRIVIT", + "PRK": "PHREAK THE 4TH", + "PRM": "PRAGMATIST", + "PRO": "PRO-FOR THE CULTURE", + "PRT": "PEROT", + "PS": "PACIFIST SOCIALIST", + "PSL": "PSL", + "PSS": "PIRATE STARSHIP", + "PUPA": "PURGE PARTY", + "PT": "PROUT", + "PU": "PURITAN", + "PUE": "Puerto Rico", + "PUR": "PURPLE PARTY", + "PVT": "Private", + "PZ": "PRINCIPALITY OF ZION", + "R": "REPUBLICAN", + "RA": "RAINBOW", + "RAM": "Rambler", + "RC": "RATIONAL CITIZEN", + "RD": "REFORMED", + "RDNA": "REPUBLICAN DEMOCRATIC NO AFFILIATION", + "RE": "REAL", + "REP": "REPRESENTATIVE", + "RES": "RESTRICTED", + "RF": "REFORM", + "RGN": "REAGANITE", + "RL": "RIGHT TO LIFE", + "RO": "ROYALIST", + "RON": "RON PAUL", + "ROY": "ROYAL", + "RP": "REPRESENTITIVENESS", + "RPDM": "REPUBLICAN DEMOCRATIC", + "RTV": "RIGHT TO VOTE", + "RVA": "REVOLUTIONARY ANARCHIST", + "RW": "RIGHT WING", + "S": "SOCIALIST", + "SA": "SOCIAL ANARCHIST", + "SAME": "SAME", + "SCIW": "SHARE COMMON INTERESTS WITHIN", + "SD": "SOCIALIST DEMOCRAT", + "SE": "Self", + "SST": "SECESSIONIST", + "SEC": "SECREST PARTY", + "SECR": "SECRETO", + "SEQ": "Socialist Equality", + "SFC": "SIR FRED THE CAT", + "SH": "SKYHOOK", + "SI": "SLOTH AND INDOLENCE", + "SIN": "SINGLE", + "SIS": "SISTER PARTY", + "SL": "SOCIALIST LABOR", + "SM": "SMUCK", + "SOA": "SOCIALIST ALTERNATIVE", + "SOD": "SOCIAL DEMOCRAT", + "SP": "SOCIALIST PROGRESSIVE", + "SPA": "spaghetti", + "SPI": "SPIRITUALISM", + "SPL": "SPLIT PARTY", + "SPP": "SILLY PARTY", + "SPS": "SPUSA", + "SPU": "SOCIALIST PARTY USA", + "SQ": "S.Q.U.I.D.", + "SR": "SQUIRREL REFORM", + "SSU": "SOVIET SOCIALIST UNION", + "SUP": "THE SURPRISE PARTY", + "SV": "SPLIT VOTE", + "SW": "SOCIALIST WORKERS", + "SWP": "SWP", + "T": "TAXPAYERS", + "TB": "TRUTH BASED", + "TFP": "THE FUN PARTY", + "TH ": "THE HUMANITY PARTY", + "TGPU": "THE GREEN PARTY OF THE UNITED", + "THP": "TRANSHUMANIST PARTY", + "THPY": "Third Party", + "THR": "THREE PERCENTER PARTY", + "TNP": "The New President", + "TO": "TOGA", + "TP": "Tea Party", + "TPC": "Tea Party Conservative", + "TPP": "Tea Party Patriot", + "TRP": "TRUMP", + "TVP": "TVP", + "TWSP": "TAX WALL STREET PARTY", + "TWVP": "TWELVE VISIONS PARTY", + "U": "UNITARIAN", + "UAT": "UNITED AMERICAN TAXPAYERS", + "UC": "UNITED CONSTITUTION", + "UDC": "UNDECLARED", + "UDCL": "UNDISCLOSED", + "UK": "UNITED KNOWLEDGE", + "UL": "US LABOR", + "UA": "UNITED AMERICA", + "UNA": "UNAFFILIATED", + "UNC": "UNCERTAIN", + "UND": "UNDECIDED", + "UNDT": "UNDETERMINED", + "UNER": "UNENROLLED", + "UNK": "UNKNOWN", + "UNPP": "United Progressive Party", + "UNS": "UNSURE", + "UP": "UNITED PEOPLE'S", + "UPA": "United Party of America", + "UPP": "U.S. Pirate Party", + "US": "U.S. SOCIALIST", + "USA": "USA", + "USC": "US CONSTITUTION", + "USM": "USA MINUTEMEN", + "USMJ": "USMJ PARTY", + "USP": "UNITED STATES PIRATE", + "UT": "US TAXPAYERS", + "UTP": "Utopian", + "UU": "U", + "UW": "UWSA", + "UWS": "UNITED WE STAND", + "V": "VOTE", + "VFI": "VOTE FOR WHO I LIKE @ THE TIME", + "VIG": "VIGILANTE", + "VP": "VETERAN'S PARTY OF AMERICA", + "WFP": "WORKING FAMILIES PARTY", + "WH": "WHIG", + "WHO": "whoever", + "WR": "WIG-REPUBLICAN", + "WI": "WILD", + "WIC": "WHOMEVER I CHOOSE", + "WIG": "WIG", + "WIL": "WHATEVER I LIKE", + "WIO": "WHEN ITS OBAMA", + "WIS": "WILL SEE", + "WITB": "WHO I THINK IS BEST", + "WIW": "WHOEVER I WANT", + "WJW": "WHAT JESUS WANTS", + "WL": "WHITE LOTUS", + "WN": "White Nationalist", + "WOR": "WORKERS WORLD", + "WP": "WORKERS PARTY", + "WPP": "WORKING PEOPLE'S", + "WWP": "WORLD WORKERS PARTY", + "WS": "Wynd Sok", + "WTBC": "WHOEVER WILL BE THE BEST CANID", + "WTH": "WILLING TO HELP", + "X": "X", + "YI": "YOUTH INTERNATIONAL", + "YO": "YOUNG OUTSIDER", + "YVIS": "YOUR VOTE IS SECRET" +} From b61efcf4296c60c44e51750c04d20934b1bbb486 Mon Sep 17 00:00:00 2001 From: Yifei SUN <100406743+miaomiao612@users.noreply.github.com> Date: Sun, 27 Nov 2022 16:36:25 -0500 Subject: [PATCH 30/33] Add files via upload --- site/js/list.js | 45 +++++++++++++++++++++++-------------------- site/js/main.js | 8 ++++---- site/js/managedata.js | 12 ++++++++---- site/js/map.js | 13 +++++++++---- 4 files changed, 45 insertions(+), 33 deletions(-) diff --git a/site/js/list.js b/site/js/list.js index 469205d..4c6ace1 100644 --- a/site/js/list.js +++ b/site/js/list.js @@ -2,37 +2,40 @@ import{htmlToElement} from './template-tools.js'; function ShowVotersList(votersToShow,onFailure) { - fetch(`./data/voters_lists/${votersToShow}.csv`) - .then(response => { - if (response.status === 200) { - const data = response.text(); - return data; - } else { - alert('Oh no, I failed to download the data.'); - if (onFailure) { onFailure() } + fetch(`data/voters_lists/${votersToShow}.csv`) + .then(resp => { + if (resp.status === 404) { + alert(`No list "${precinct}" is available.`) + throw new Error(`No data file for list "${precinct}"`) } - }) + return resp + }) .then(v => Papa.parse(v, { delimiter:"," })) .catch(err => console.log(err)) .then(result => { let v = result.data.slice(1, result.data.length-1); + return v; - //now we have many voters of certain list.no in a json format - for (const voter in result){ - const html = ` -
      • ${voter['name']} (id: ${voter['ID Number']})
      • - `; - const li = htmlToElement(html); - }//display voter's name and ID - } - ) - - + }) -} + //now we have many voters of certain list.no in a json format + .then(result =>{ + let D=result.map(showlist) + return D;} + ) +} + //display voter's name and ID +function showlist(votersToShow) { + List.innerHTML=''; + const html = ` +
      • ${votersToShow['name']} (id: ${votersToShow['ID Number']})
      • + `; + const li = htmlToElement(html); + List.append(li); +} export{ diff --git a/site/js/main.js b/site/js/main.js index 39e0bca..9b52932 100644 --- a/site/js/main.js +++ b/site/js/main.js @@ -23,12 +23,12 @@ import { ShowVotersList } from './list.js'; let voterMap=initMap(); let votersToShow = document.querySelector('#listNo'); let search = document.querySelector('#search1'); +let List = document.querySelector("#voter-list"); +Search(voterMap, search, votersToShow); -//let btn = document.getElementById("search1"); -//btn.addEventListener("click", csvtojson(voterMap, votersToShow)); // **Geolocation** -- `onUserPositionSuccess` will be called by the geolocation // API if and when the user's position is successfully found. @@ -42,14 +42,14 @@ function onUserPositionSuccess(pos) { console.log(err); } - + +//setupGeolocationEvent(); function setupGeolocationEvent() { navigator.geolocation.getCurrentPosition( onUserPositionSuccess, onUserPositionFailure, ); } - Search(voterMap, search, votersToShow); //setupGeolocationEvent(); ShowVotersList(votersToShow); diff --git a/site/js/managedata.js b/site/js/managedata.js index caf12f5..ca2ab78 100644 --- a/site/js/managedata.js +++ b/site/js/managedata.js @@ -1,7 +1,8 @@ import { showVotersOnMap } from './map.js'; -//convert csv to json +//convert csv to json and display on map function csvtojson ( map, votersToShow, onFailure){ - fetch(`./data/voters_lists/${votersToShow}.csv`) + fetch(`data/voters_lists/${votersToShow}.csv`) + .then(response => { if (response.status === 200) { const data = response.text(); @@ -16,11 +17,14 @@ function csvtojson ( map, votersToShow, onFailure){ .then(result => { let v = result.data.slice(1, result.data.length-1); return v; - }) + //now we get json version data of a certain listNO. + .then(result => showVotersOnMap(result,map)) + + } - + export{ csvtojson, }; \ No newline at end of file diff --git a/site/js/map.js b/site/js/map.js index 004c72c..0b06582 100644 --- a/site/js/map.js +++ b/site/js/map.js @@ -7,6 +7,7 @@ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE */ import{ csvtojson } from './managedata.js'; +import{ ShowVotersList } from './list.js'; function onvoterClicked(evt) { console.log(evt); @@ -65,15 +66,18 @@ function makevoterFeature(voter) } //Use the function to display the voters' location on the map. -function showVotersOnMap(votersToShow, voterMap) { +function showVotersOnMap(votersToShow_json, voterMap) { if (voterMap.voterLayer !== undefined){ voterMap.removeLayer(voterMap.voterLayer); } const voterFeatureCollection = { "type": "FeatureCollection", - "features": votersToShow.map(makevoterFeature),//excuate one by one + "features": votersToShow_json.map(makevoterFeature),//excuate one by one, convert json like data to geojson like feature + }; + + voterMap.voterLayer = L.geoJSON(voterFeatureCollection, { pointToLayer: (feature, latlng) => L.circleMarker(latlng), style: { @@ -92,8 +96,9 @@ function showVotersOnMap(votersToShow, voterMap) { function Search (map, search, votersToShow) { search.addEventListener('click', () => { let votersToShow1 = votersToShow.value; - let result = csvtojson(map, votersToShow1); - showVotersOnMap(result, map); + csvtojson(map, votersToShow1); + ShowVotersList(votersToShow1); + }); } From 4fcc9a915ab268677353bf8eb82d9bdcd4c14d21 Mon Sep 17 00:00:00 2001 From: Yifei SUN <100406743+miaomiao612@users.noreply.github.com> Date: Sun, 27 Nov 2022 18:42:57 -0500 Subject: [PATCH 31/33] Add files via upload --- site/js/list.js | 30 +++++++++++++++--------------- site/js/main.js | 4 ++-- site/js/map.js | 2 +- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/site/js/list.js b/site/js/list.js index 4c6ace1..25e63a0 100644 --- a/site/js/list.js +++ b/site/js/list.js @@ -1,21 +1,23 @@ import{htmlToElement} from './template-tools.js'; function ShowVotersList(votersToShow,onFailure) { - + //let votersToShow1 = votersToShow.value; fetch(`data/voters_lists/${votersToShow}.csv`) - .then(resp => { - if (resp.status === 404) { - alert(`No list "${precinct}" is available.`) - throw new Error(`No data file for list "${precinct}"`) + + .then(response => { + if (response.status === 200) { + const data = response.text(); + return data; + } else { + alert('Oh no, I failed to download the data.'); + if (onFailure) { onFailure() } } - return resp - }) + }) .then(v => Papa.parse(v, { delimiter:"," })) .catch(err => console.log(err)) .then(result => { let v = result.data.slice(1, result.data.length-1); return v; - }) //now we have many voters of certain list.no in a json format @@ -28,13 +30,11 @@ function ShowVotersList(votersToShow,onFailure) { //display voter's name and ID function showlist(votersToShow) { - List.innerHTML=''; - const html = ` -
      • ${votersToShow['name']} (id: ${votersToShow['ID Number']})
      • - `; - const li = htmlToElement(html); - List.append(li); - + const resultItem = document.createElement('li') + resultItem.classList.add('result-item') + const text = document.createTextNode(votersToShow.name) + resultItem.appendChild(text) + list.appendChild(resultItem) } diff --git a/site/js/main.js b/site/js/main.js index 9b52932..ac3cef1 100644 --- a/site/js/main.js +++ b/site/js/main.js @@ -23,7 +23,7 @@ import { ShowVotersList } from './list.js'; let voterMap=initMap(); let votersToShow = document.querySelector('#listNo'); let search = document.querySelector('#search1'); -let List = document.querySelector("#voter-list"); +//let List = document.querySelector("#voter-list"); Search(voterMap, search, votersToShow); @@ -51,7 +51,7 @@ function setupGeolocationEvent() { ); } //setupGeolocationEvent(); -ShowVotersList(votersToShow); +//ShowVotersList(votersToShow); diff --git a/site/js/map.js b/site/js/map.js index 0b06582..fdb33b5 100644 --- a/site/js/map.js +++ b/site/js/map.js @@ -92,7 +92,7 @@ function showVotersOnMap(votersToShow_json, voterMap) { } -//use this function to search the voters by listNo +//designed for the "search" buttom, use this function to search the voters by listNo. both on map and lists function Search (map, search, votersToShow) { search.addEventListener('click', () => { let votersToShow1 = votersToShow.value; From 608f54a6bd9737cf4e0459119e1d7588998d2636 Mon Sep 17 00:00:00 2001 From: miaomiao612 Date: Sun, 11 Dec 2022 04:26:08 +0800 Subject: [PATCH 32/33] update --- .vscode/settings.json | 2 +- site/index.html | 2 +- site/js/main.js | 4 ++-- site/js/template-tools.js | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 5774974..404d32a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,3 @@ { - "liveServer.settings.port": 8082 + "liveServer.settings.port": 8084 } \ No newline at end of file diff --git a/site/index.html b/site/index.html index 8982d1d..fc2ff9c 100644 --- a/site/index.html +++ b/site/index.html @@ -2,7 +2,7 @@ * @Author: miaomiao612 dddoctorr612@gmail.com * @Date: 2022-11-10 05:49:08 * @LastEditors: miaomiao612 dddoctorr612@gmail.com - * @LastEditTime: 2022-11-16 01:13:17 + * @LastEditTime: 2022-12-03 04:46:16 * @FilePath: \voter-canvassing\site\index.html * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE --> diff --git a/site/js/main.js b/site/js/main.js index ac3cef1..ac08931 100644 --- a/site/js/main.js +++ b/site/js/main.js @@ -35,14 +35,14 @@ Search(voterMap, search, votersToShow); function onUserPositionSuccess(pos) { updateUserPositionOn(voterMap, pos); } - + // **Geolocation** -- `onUserPositionSuccess` will be called by the geolocation // API if and when there is an error in finding the user's position. function onUserPositionFailure(err) { console.log(err); } - + //setupGeolocationEvent(); function setupGeolocationEvent() { navigator.geolocation.getCurrentPosition( diff --git a/site/js/template-tools.js b/site/js/template-tools.js index b4e9248..6cc7d40 100644 --- a/site/js/template-tools.js +++ b/site/js/template-tools.js @@ -10,7 +10,7 @@ for more information: https://stackoverflow.com/a/35385518/123776 * @param {String} HTML representing a single element * @return {Element} */ - function htmlToElement(html) { +function htmlToElement(html) { const template = document.createElement('template'); const trimmedHtml = html.trim(); // Never return a text node of whitespace as the result template.innerHTML = trimmedHtml; From 7e1d0c98de04d2e0c068f14f8aa0027c40e4d084 Mon Sep 17 00:00:00 2001 From: Yifei SUN <100406743+miaomiao612@users.noreply.github.com> Date: Fri, 23 Dec 2022 02:07:23 +0800 Subject: [PATCH 33/33] Update README.md --- README.md | 72 ------------------------------------------------------- 1 file changed, 72 deletions(-) diff --git a/README.md b/README.md index c690e2e..8b13789 100644 --- a/README.md +++ b/README.md @@ -1,73 +1 @@ -# Voter Canvassing App -### Team members: -* Yifei Sun -* Xuening Zhang -* Tom Sun -## Core Interface Elements - -### Layout - -* [ ] Unless otherwise specified, all features should be useable on both small (mobile) and large (laptop/desktop) screens. **Your HTML document should have appropriate `meta` tag(s) to make this possible.** - -### Loading voter files... - -* [ ] There should be an `input` element on the page where you can enter a voter file number. **Save the `input` DOM element in a variable named `voterFileInput` attached to the global `window` object.** In other words: - - ```js - window.voterFileInput = ...; - ``` - -* [ ] There should be a `button` that will load the voter file number given in the `voterFileInput` when clicked. **Save the `button` DOM element in a variable named `voterFileLoadButton` attached to the global `window` object.** - -### Listing and mapping voters... - -* [ ] Your page should have an element that shows the voters (and their addresses) from a file. Note that the element _does not_ need to be a `ul`, `ol`, or any other HTML list element. Even though the element itself may not use a list tag like `ul` or `ol`, it will still function as a list and I'll still refer to it as one. **The list's DOM element should be available on the global `window` object as a variable named `voterList`.** - -* [ ] Your page should have a Leaflet map to show voter locations. **The Leaflet map object should be available on the global `window` object as a variable named `voterMap`.** - -* When you enter a file number, the voter information in that CSV file should be loaded onto the `voterMap` and into the `voterList`. - * [ ] **Wrap each voter's name in an element (for example a `span`) with the class `voter-name`. Wrap addresses in an element with the class `voter-address`** You may choose to list each voter individually or grouped by address, which I would recommend. Either way, each voter's basic information (at least their name and street address) should be shown in the `voterList`. - * [ ] **Represent the voters in the file with map markers.** You may choose to have one map marker to represent each voter, one marker to represent each address, or one marker to represent each _building_ (for example, two apartments that share the same street address are in the same building). I would generally recommend showing a marker for each building, as otherwise markers for different apartments or voters in the same building will be overlapping. - -* [ ] When you click on a map marker, the marker should be highlighted in some way to show that it is selected. **Change the marker styles of a selected marker if it is a vector marker (e.g. `L.circleMarker`), or change the icon if it is a normal image marker (e.g. `L.marker`).** - -* [ ] When you click on a map marker, the corresponding item(s) in the `voterList` should also be highlighted. **Add a class named `selected` to the appropriate element(s) within the `voterList`.** Use that `selected` class to apply different visual styles to the element(s). - -### Displaying and editing voter details... - -> _Note that if you decide to implement a workflow that doesn't precisely fit into the structure below, that's ok! Just talk with me about what the workflow is, because we may need to modify the project tests._ - -* [ ] When you click on a voter (or an address) in the `voterList`, a panel should be shown that contains details about the voter (or about each voter at the address). This panel could be represented in HTML with a `div`, `form`, `section`, or any of a number of other elements. **Give the voter information panel(s) a class of `voter-details`.** - -* [ ] There should be _at least_ three separate input elements available for collecting facts about each voter (refer to the [product requirements document](PRD.md) that we created in class to remind yourself what kind of information should be collected). **Include fields for collecting voter information on each `voter-details` panel.** - -* [ ] There should be a button on the voter details panel that allows a user to save the information entered when it is clicked. **Include such a button and give it a class `voter-details-save-btn`.** - -* [ ] Voter details should be persisted to local memory. **When voter details are closed, the page is reloaded, and the voter information is loaded again, the value in each of the inputs in the `voter-details` panel should be recalled.** - -## Stretch 1: Store Voter Details in the Cloud - -* In addition to saving data locally on a single browser, make it so that voter data will be recalled regardless of the device you're using. - -## Stretch 2: User Feedback - -* Use a toast or some other type of notification method to let the user know that their data has been successfully saved. -* Give the user gamified feedback such as toasts or alerts when they're a certain amount of the way through the voter file. - -## Stretch 3: High-level Voter File Stats - -* Include a view (either on the same HTML page or a different one) where you can display high-level summary charts and info about a voter file, such as: - * the proportion of each political party represented in the file, - * the number/proportion of doors you've already knocked on, or - * the number/proportion of people you've already talked to from the file. - -## Stretch 4: Voting Record - -* Include a voter's voting record information in the voter details, ordered by their participation in elections from most recent to least recent. - -## Stretch 5: Geolocation - -* Show the closest voters that the user hasn't yet visited at the top of the address list. This way the user should always be able to simple look at the next voter/address in the list. - - > Note: this can be done using (1) the [geolocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API), (2) a library like [turf.js](https://turfjs.org/), and (3) JavaScript's [`Array.sort` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) which can admittedly be pretty weird at first.