Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stylistic adaptions force graph #43

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 36 additions & 5 deletions code/src/lib/dataVisComponents/ForceGraph.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,10 @@
return {source:`${i}-0`, target:`${i}-${e}`}
})).flat()

fig_size = Math.min(width, height)/18
console.log("links")
console.log(links)

fig_size = Math.min(width, height)/23

var node = d3.select(g)
.selectAll("image")
Expand All @@ -99,17 +102,41 @@
.attr("onmouseout", d => `this.style.opacity=${d.dark ? 0.3 : 1}`)
.style("filter", d => d.protagonist ? filters[6] : filters[d.category])
.style("opacity", d => d.dark ? 0.3 : 1.0)
// Example of setting initial positions based on category
.attr("x", d => width / 2 - (d.category * 1000 - d.category % 2 * 2000)) // Provide a larger offset
.attr("y", d => height / 2 + (d.category % 2 * 100)) // Alternate vertically based on even/odd category


var simulation = d3.forceSimulation(data2)
.alpha(0.3)
.alphaDecay(0.022)
.velocityDecay(0.6)
.force("center", d3.forceCenter().strength(fcenter).x(width/2).y(height/2))
.force("charge", d3.forceManyBody().strength(fcharge))
.force("collide", d3.forceCollide().strength(fcollide).radius(fig_size/2).iterations(1))
.force("link", d3.forceLink().strength(flink).id(d => d.id))
.force("charge", d3.forceManyBody().strength(-5)) // Try adjusting strength
.force("collide", d3.forceCollide().radius(() => fig_size))
.force("link", d3.forceLink(links).id(d => d.id).distance(2).strength(0.5))
.force("bound", () => {data2.forEach(node => {
node.x = Math.min(width - fig_size - legendWidth - legendMargin, Math.max(0, node.x));
node.y = Math.min(height - fig_size - legendMargin, Math.max(node.y, paddings.top));
})})
.force("customSeparate", alpha => {
data2.forEach(d => {
data2.forEach(other => {
if (d.category !== other.category) { // Assuming each node has a 'group' attribute
let dx = d.x - other.x;
let dy = d.y - other.y;
let dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 10) { // Define a threshold for separation
let force = alpha * 2 / dist**2; // Adjust force magnitude as needed
d.vx += dx * force;
d.vy += dy * force;
}
}
});
});
})



simulation
.nodes(data2)
Expand Down Expand Up @@ -210,10 +237,14 @@
{#if selectedCategory == "age"}
About {currentHoveredPoint.value.toFixed(2)}% of inhabitants in the selected area are of age {currentHoveredPoint.label}.
{:else if selectedCategory == "race"}
{#if currentHoveredPoint.value == 'other_race'}
About {currentHoveredPoint.value.toFixed(2)}% of inhabitants in the selected area belong to another race.
{:else}
About {currentHoveredPoint.value.toFixed(2)}% of inhabitants in the selected area are {currentHoveredPoint.label}.
{/if}
{:else if selectedCategory == "gender"}
About {currentHoveredPoint.value.toFixed(2)}% of inhabitants in the selected area are {currentHoveredPoint.label}.
{:else if selectedCategory == "mean household income"}
{:else if selectedCategory == "median household income"}
{#if currentHoveredPoint.value == 5}
The top 5% of households in the selected area have a mean income of {currentHoveredPoint.label}.
{:else}
Expand Down
103 changes: 62 additions & 41 deletions code/src/lib/dataVisComponents/ForceGraphSelector.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,46 +3,67 @@

// Function to determine if the current label should be highlighted
function isSelected(value) {
return activeSelection === value ? 'selected' : '';
return activeSelection === value ? 'selected' : '';
}
</script>

<div class="radio-container">
{#each ['age', 'race', 'gender', 'mean household income', 'vehicles per household', 'mode of transportation'] as category}
<label class={isSelected(category)}>
<input type="radio" bind:group={activeSelection} name="selector" value={category}>
{category.replace(/_/g, ' ').toUpperCase()} <!-- Improved readability -->
</label>
{/each}
</script>

<div class="radio-container">
<div class="row">
{#each ['age', 'race', 'gender'] as category}
<label class={isSelected(category)}>
<input type="radio" bind:group={activeSelection} name="selector" value={category}>
{category.replace(/_/g, ' ').toUpperCase()} <!-- Improved readability -->
</label>
{/each}
</div>

<style>
.radio-container {
position: relative;
top: 16px;
left: 16px;
padding: 4px;
border-radius: 2px;
display: flex;
flex-direction: row; /* Align items horizontally */
gap: 10px; /* Add some space between items */
}

/* Basic styling for labels */
label {
cursor: pointer;
transition: font-weight 0.3s ease;
white-space: nowrap; /* Prevent labels from wrapping */
}

/* Hide the radio button */
input[type="radio"] {
display: none;
}

/* When a label is selected, make the text bold */
.selected {
font-weight: bold;
}
</style>

<div class="row">
{#each ['median household income', 'vehicles per household', 'mode of transportation'] as category}
<label class={isSelected(category)}>
<input type="radio" bind:group={activeSelection} name="selector" value={category}>
{category.replace(/_/g, ' ').toUpperCase()} <!-- Improved readability -->
</label>
{/each}
</div>
</div>

<style>
.radio-container {
display: flex;
flex-direction: column; /* Align items in columns for two rows */
gap: 10px; /* Space between rows */
padding: 4px;
border-radius: 2px;
align-items: center; /* Align the entire container's content in the center */
}

.row {
display: flex;
flex-direction: row;
gap: 10px;
justify-content: center; /* Center-align the items within each row */
}

label {
cursor: pointer;
transition: background-color 0.3s ease, color 0.3s ease;
padding: 5px 10px; /* Padding for better touch area */
border-radius: 4px; /* Rounded corners */
white-space: nowrap;
}

input[type="radio"] {
display: none;
}

label:hover {
background-color: #f0f0f0; /* Light grey background on hover */
color: #333; /* Darker text on hover */
}

.selected {
font-weight: bold;
background-color: #dedede; /* Light grey background for selected item */
}
</style>


26 changes: 17 additions & 9 deletions code/src/lib/dataVisComponents/panel.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
export let selectedStations;
export let guidedMode;

let visibility_slide12 = false;
let visibility_slide21 = false;
let visibility_slide4 = false;
let visibility_slide5 = false;

let container;
// $: console.log({ value });
let colors = [
Expand All @@ -48,13 +53,15 @@
});

// Default to true to show Slide2 initially
let isSlide2Active = 'value === 3';
let isSlide2Active = false;
console.log("isSlide2Active", isSlide2Active)
let isSlide1Active = 'value === 0';

// Reactive statement to handle changes in selectedMunicipality
$: if (ready && selectedMunicipality) {
console.log("Selected Municipality is set", selectedMunicipality);
let value_scroll = 5; // Assuming this is the index for Slide21
visibility_slide21 = 'value === 4'
let value_scroll = 4; // Assuming this is the index for Slide21
// isSlide1Active = true;
scrollToSlide(value_scroll, () => {
// This callback is called after the scrolling animation completes
Expand All @@ -69,7 +76,8 @@

$: if (ready && firstStation) {
console.log("Selected station is set")
let value_scroll_station = 4;
visibility_slide4 = 'value === 5'
let value_scroll_station = 5;
scrollToSlide(value_scroll_station)
}

Expand Down Expand Up @@ -124,21 +132,21 @@

</script>

<div class="panel" style="position: absolute; top: 0; left: 0; width: 40%; height: 100%; background-color: rgba(0, 0, 0, 0.6); padding: 20px; color: {colors[3]};">
<div class="panel" style="position: absolute; top: 0; left: 0; width: 40%; height: 100%; background-color: rgba(0, 0, 0, 0.8); padding: 20px; color: {colors[3]};">
<Scrolly bind:this={scrollyComponent} bind:value> <!-- 3. This is what updates value -->
<!-- {#each ['MARGINAL', 'OR', 'World!'] as text, i}
<div class="step" class:active={value === i}>
<p>{text}</p>
</div>
{/each} -->
<Slide1 active={isSlide1Active} />
<Slide11 active={value === 1} bind:value/>
<Slide12 active={value === 2} bind:value/>
<Slide11 active={value === 1} bind:value bind:visibility_slide12={visibility_slide12}/>
<Slide12 active={visibility_slide12} bind:value bind:isSlide2Active={isSlide2Active}/>
<Slide2 active={isSlide2Active} bind:municipalities={municipalities} bind:selectedMunicipality={selectedMunicipality}/>
<Slide21 active={value === 4} bind:municipality={selectedMunicipality} bind:station={firstStation} bind:value/>
<Slide21 active={visibility_slide21} bind:municipality={selectedMunicipality} bind:station={firstStation} bind:value/>
<!-- <Slide3 active={value === 4} bind:municipality={selectedMunicipality} bind:station={firstStation}/> -->
<Slide4 active={value === 5} bind:municipality={selectedMunicipality} bind:station={firstStation} bind:value/>
<Slide5 active={value === 6} bind:municipality={selectedMunicipality} bind:station={firstStation}/>
<Slide4 active={visibility_slide4} bind:municipality={selectedMunicipality} bind:station={firstStation} bind:value bind:visibility_slide5={visibility_slide5}/>
<Slide5 active={visibility_slide5} bind:municipality={selectedMunicipality} bind:station={firstStation}/>
<Slide6 active={value === 7} />
</Scrolly>
</div>
Expand Down
16 changes: 11 additions & 5 deletions code/src/slides/Slide1.1.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,29 @@
import { observerStore } from '../lib/panelComponents/Scrolly_slide';

export let value = 0;
let isVisible = false;
let isVisible_slide1 = false;
export let visibility_slide12 = false;

const unsubscribe = observerStore.subscribe(store => {
isVisible = store.isVisible;
isVisible_slide1 = store.isVisible;
});

$: if (isVisible_slide1) {
console.log(visibility_slide12)
visibility_slide12 = 'value === 2';
console.log("Slide12 is now visible")
console.log(visibility_slide12)
}

// Reactive statement to monitor changes in value
$: if (value === 1) {
console.log(isVisible)
observerStore.startObservation();
console.log(isVisible)
}
</script>

<div class="slide">
<h1>What is the MBTA Communities Act?</h1>
{#if isVisible}
{#if isVisible_slide1}
<h2>
The MBTA Communities Act is a 2021 Massachusetts state law that aims to reduce the housing crisis by requiring cities near MBTA stations to upzone at least one area within their borders, allowing multi-family housing without an extensive permitting process. Massachusetts governor Maura Healy has stated that noncompliance could result in result in not only a loss of state funding for housing but also potential legal action. <br>
</h2>
Expand Down
37 changes: 19 additions & 18 deletions code/src/slides/Slide1.2.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,49 +3,50 @@
import { observerStore } from '../lib/panelComponents/Scrolly_slide';

export let value = 0;
let isVisible = false;
let isVisibleSecond = false;
let isVisible_slide12 = false;
let isVisibleSecond_slide12 = false;
export let isSlide2Active;

observerStore.subscribe(store => {
isVisible = store.isVisible;
isVisible_slide12 = store.isVisible;
});

$: if (value === 2) {
observerStore.resetVisibility(); // Reset visibility whenever checking this condition
// observerStore.resetVisibility(); // Reset visibility whenever checking this condition
console.log("observation started")
observerStore.startObservation();
}

$: if (isVisible) {
$: if (isVisible_slide12) {
console.log("entered", isVisible_slide12)
setTimeout(() => {
isVisibleSecond = true;
isVisibleSecond_slide12 = true;
}, 15000);
console.log("is visible second slide12 now true")
}
$: if (isVisibleSecond_slide12 == true) {
console.log("is visible", isVisibleSecond_slide12)
isSlide2Active = 'value === 3';
console.log("slide 2 is now active", isSlide2Active)
}
</script>


{#if (active)}
<div class="slide">
<h1>What are the controversies?</h1>
{#if isVisible}
{#if isVisible_slide12}
<h2>
While broadly supported, the law faces controversy, especially in lower-density suburbs served by MBTA Commuter Rail. As of April 2024, all 177 communities have submitted appropriate zoning proposals to the state and thus are technically compliant with the law, but many, including Holden, Rockford, and Bourne, raised significant legal challenges along the way, and whether all communities will become compliant remains to be seen. On the other hand, some communities, such as Brookline, have embraced the legislation and have passed new zoning regulations that go above and beyond the law’s requirements. <br>
</h2>
{/if}
<br>
{#if isVisibleSecond}
{#if isVisibleSecond_slide12}
<h2>
Though critics have claimed that upzoning these suburban communities would significantly change the urban form of low-density communities in culturally incompatible ways, it is essential to understand that the MBTA Communities Act does not directly dictate what type of housing is built in these communities. It simply requires a single district within the municipality where some form of multifamily housing is allowed by right. This gives local governments significant influence on the location and nature of their multifamily districts. <br>
</h2>
{/if}
</div>

<!-- <div class="footnotes">
<ol>
<li id="fn1">
https://www.wbur.org/radioboston/2023/11/27/mbta-communites-act-density-transit-oriented-housing
<a href="#fnref1">↩</a>
</li>
</ol>
</div> -->
{/if}

<style>
@import url("$lib/slide.css");
Expand Down
Loading