Svelte app for the job quality/segregation project, January 2024. This project is a single page SvelteKit application that uses svelte-scroller
, Layer Cake
, and d3-force
to create a scrollytelling page featuring a unique radial visualization.
Data Visualization and Development: Ben Kates
Designer: Brittney Spinner
Writer: Wes Jenkins
Research team: Ofronama Biu, Batia Katz, Afia Adu-Gyamfi, Molly M. Scott
Production: https://apps.urban.org/features/job-quality-segregation-race-gender/
The project uses several data files:
data.json
: All 108 jobs and associated metrics for each of the six groups.occupation-data.json
: Names and metadata for each occupationindustry-data.json
: Names and metadata for each industry (occupation group)group-count-data.json
: Summarized occupation count of crowding categories for each of the six groups, split by above/below quality occupationsaria-label-radial-data.json
:aria-label
for each of the radial charts in the sixCard
componentscredits-data.json
: Project creditsindicator-names.json
: List of 11 indicators
Components found in this single page application src/routes/+page.svelte
. These are the components/folders that contain the content-specific features of the page:
Intro
: Introduction paragraphsScrolly
: Scrollytelling section, including infographicOccupation
: Occupation section above "tool" section, title and indicator list with scores for eachCard
: Card for the "tool" section of the pageRadial
: Layer Cake-based Radial visualization consisting of nodes, guides, and linesFooter
: About, data sources, and credits
This project uses v0.3.1
of the open source @urbaninstitute/dataviz-components library, consisting of Svelte components and helper functions/stores.
This project uses svelte-scroller
from Rich Harris to create the scrollytelling section of the page. The only change in approach in this project is the padding of the foreground determines space between foreground steps (not view height aka vh
).
See src/lib/utils/scrollySteps.js
for the metadata of active/emphasized Radial
layers.
This project uses Layer Cake to maintain scales and placement of components for the radial visualization. See Radial.svelte
for the definition of scales (x/y/color) and custom props that are passed down via Svelte context. The Card
component declares the context for the specific race/gender "group".
d3-force
is utilized in the RadialNodes
component, which uses a custom forceRadial
function to add an angular offset to the radial layout. This is necessary to maintain the "pie" shape of the visualization, as the default d3.forceRadial
function does not allow for this. See the "Utility Functions" section in this README for more info.
In order to create the many layers of the visualization, the child components of Radial
are:
RadialCrowdingCircles
: Background circles for each crowding designation (concentric circles starting from the center working out)RadialQualityGuides
: Background lines for each quality score 1-10RadialCrowdingText
: Crowding designation text within circles crowding circles (ie: "Crowded Out", "Proportional", "Crowded In")RadialNodeArea
: Circular background area for a particular quality score and crowding designation coordinate, based on the selected occupationRadialNodes
: 108 nodes for each occupationRadialQualityNums
: Quality score numbers 1-10RadialQualityText
: Guiding text for quality score direction, placed on outermost circles
These components reference the custom
Layer Cake context, to determine the UI type (scrolly vs. card) and the scroll index (current step in the scrolly). Additionally, RadialTooltip.html.svelte
has been added for tooltip functionality in the <Html>
child of the Layer Cake parent.
selected_occ_ind.js
: Stores for the selected occupation and industry (occupation group), along with derived stores for derived metadata.
ariaLabelRadial.js
: Renders a dynamicaria-label
based onsrc/data/aria-label-radial-data.json
forceRadial.js
: Replacement for d3'sforceRadial
that adds angular offset (from this Observable notebook by Philippe Rivière aka Fil)helper.js
: Helper functions for getting a crowding label/color based on crowding designation number as well as a "radial path" that draws a circle based on a given width/height and radiusscrollySteps.js
: Metadata for active/emphasized steps ofRadial
layerssvg-partial-circle.js
: Renders a partial circular path for use in the background text of "Proportional" label inRadialCrowdingText.svelte
, adapted from Jannis R's repo
In order to maintain consistent height for dynamic text (namely long occupation titles) and not affect the user experience, this project uses an external Svelte package svelte-textfit
. This package is based on react-textfit
.
This has been copied locally to maintain specific Svelte 4 features in the following locations:
utils/text-fit/text-fit-action.js
utils/text-fit
To set up the project locally, install dependencies and run:
npm install
npm run dev