-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathdata.qmd
More file actions
180 lines (130 loc) · 7.16 KB
/
Copy pathdata.qmd
File metadata and controls
180 lines (130 loc) · 7.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
---
title: "Data Sources and Details"
subtitle: "Where we got it, how we made it"
format:
html:
theme: [cosmo,assets/side.scss]
---
## Why Bigfoot sightings?
Why not Bigfoot sightings??????
This project was adapted from a bigfoot shiny dashboard Russ built a while back. The full dashboard can be seen <a href= "https://russellshean.shinyapps.io/bigfoot_sightings2/">here</a>
Data source, scraping, and processing details can be found here in [Russell's GitHub repo](https://github.com/Russell-Shean/bigfoot_sightings).
The GitHub repo also, (sort of), explains how we built the interactive leaflet map and the rest of the shiny dashboard including its custom Javascript and CSS.
tl;dr - The data was scraped from a [bigfoot sightings database](https://www.bfro.net/GDB/) using a python script, cleaned in R, and then Russell made a sweet Shiny app displaying the results. We then adapted the outputs for this closeread doc.
## How we made it
The closeread page (plus Quarto in general) was both easy and challenging at times. Here are some of the challenges + lessons learned:
1. The parallax effect was a pain to figure out but [this video](https://youtu.be/Jt2yNZdOHxQ?si=cUVVBhRDzsXhPu7_) helped a ton
- I had to adapt the html/css in that video to work with Quarto by making a custom html called `before.html` and putting it in the header like this:
```yaml
---
format:
closeread-html:
include-in-header: assets/before.html
---
```
2. I used the [amazing artwork by Tati.Dsgn](https://www.vecteezy.com/vector-art/5565275-silhouette-landscape-with-fog-forest-pine-trees-purple-mountains-illustration-of-view-mist-and-sunset-good-for-wallpaper-background-banner-cover-poster) to get the parallax background
- I had to save that art and unwrap all the layers using Figma in order to get the dark treeline as a separate image that 'covers' the background as the user scrolls. Figma is a great tool for editing images like that.
3. The actual closeread stuff was straightforward _until_ the ojs stuff :(
- I wanted to make a map that adds markers when the user scrolls down, like this in the [closeread docs](https://closeread.dev/gallery/demos/ojs-variables/)
- I spent hours with chatGPT and reading that document...
- I had an issue when it came to combining the ojs leaflet map I created alongside the tweaked html for the parallax effect - the two did not mix well at all. Let me explain:
The closeread docs for ojs are great. They use `crProgressBlock` as a variable to indicate how far along the page a user has scrolled.
They then take that variable and apply some basic math to it. For example, when the user starts scrolling at 0%, they set the variable `angle1` to be `-180`. And `angle1` will change as the user scrolls down until it gets to angle = `0`. Like this:
```markdown
angleScale1 = d3.scaleLinear()
.domain([0, 1])
.range([-180, 0])
.clamp(true)
angle1 = angleScale1(crProgressBlock)
```
I wanted to do this for my ojs leaflet map; when a user scrolls, the markers (bigfoot icons and info) get added to the map.
I can add markers to the map like this, where it takes in the lat and lon of the point and plots it:
```{ojs}
//| echo: true
//| eval: false
L.marker([lat, lon], { icon: BigFootIcon })
.addTo(map);
```
But, I want the points to be added based on the year variable they have in the dataset. So when a user scrolls, the year increases and the data points are filtered to add more to the map.
I tried it like in the closeread docs by using `crProgressBlock` but this **WILL NOT WORK in my case** :
```{ojs}
//| echo: true
//| eval: false
bfScale1 = d3.scaleLinear()
.domain([0, 1])
.range([1920, 2025])
.clamp(true)
bf1 = bfScale1(crProgressBlock)
```
In my parallax set up, I have this in my scss file:
```scss
html {
overflow: hidden;
}
```
It's necessary for the scroll effect, but it also means that the scroll counter gets messed up and will no longer count a user's scroll progress on the page.
So I used a different variable to track a user's progress instead, the `crTriggerIndex`:
```{ojs}
//| echo: true
//| eval: false
bfScale2 = d3.scaleLinear()
.domain([1, 5])
.range([1930, 2020])
.clamp(true)
bf2 = bfScale2(crTriggerIndex)
```
Now, as the user scrolls, the TriggerIndex counts progress to where they are at on the page _according to the scrolly trigger_. So like, if I have a cr-section along with 5 text points in my sidebar, it will divide the crTriggerIndex into 5 numbers, The 1st being the first scroll trigger, and increase my variable based on the proceeding triggers, like this:
```yaml
::::{.cr-section}
trigger 1 @cr-map # bf2 = 1930
trigger 2 @cr-map # bf2 = 1960
trigger 3 @cr-map # bf2 = 1980
trigger 4 @cr-map # bf2 = 2000
trigger 5 @cr-map # bf2 = 2020
:::{#cr-map}
sticky section here with my map
:::
::::
```
And it looks like this to where I can use my counting variable to dynamically filter the dataset when the user scrolls (and add the filtered dataset points to the map)
```{ojs}
//| echo: true
//| eval: false
// Filter the points based on the year (properties.year)
fp = bf_points.features.filter(feature => {
const year = parseInt(feature.properties.year); // Convert year to integer
return year <= bf2; // Only keep points with year less than or equal to bf2
});
// Add markers for each filtered point
fp.forEach(feature => {
const lat = feature.geometry.coordinates[1]; // Latitude from GeoJSON
const lon = feature.geometry.coordinates[0]; // Longitude from GeoJSON
L.marker([lat, lon], { icon: BigFootIcon })
.bindPopup(`
<p><strong>${feature.properties.summary}</strong></p>
<p><strong>Report Date: </strong>${new Date(feature.properties.report_date).toLocaleDateString()}</p>
<p><strong>Classification: </strong>${feature.properties.classification}</p>
<p><strong>Environment: </strong>${feature.properties.environment}</p>
<a href="${feature.properties.url}" target="_blank">Read full report</a>
`)
.addTo(map);
});
```
## General Advice
This is all very hacked together. I was pasting random code from chatGPT and other leaflet maps I found on the web to cobble this together. It's rough, but feels good to have it somewhat work.
If you want to use and OJS cell like this, I cannot recommend adding this to your testing document enough. Put this outside of a cr-section so that you can see all the attributes of your scrolling variables. It will let you see how your custom variables get derived based on where the user is on the page:
````yaml
:::{.counter style="position: fixed; top: 10px; right: 10px; background-color: skyblue; border-radius: 5px; padding: 18px 18px 0 18px; line-height: .8em;"}
```{ojs}
md`Active sticky: ${crActiveSticky}`
md`Active trigger: ${crTriggerIndex}`
md`Trigger progress: ${(crTriggerProgress * 100).toFixed(1)}%`
md`Scroll direction: ${crDirection}`
md`Progress Block progress: ${(crProgressBlock * 100).toFixed(1)}%`
md`-----`
md`(derived) derived var1: ${bf1.toFixed(1)}°`
md`(derived) bf2: ${bf2.toFixed(1)}`
```
:::
````
If all else fails, post a discussion in the closeread github site and feel free to tag me. I'd be happy to help and/or learn more about this stuff!