Unlisted
Edited
Apr 2, 2024
Insert cell
Insert cell
UBX_FACULTYVIZ = htl.html`
<div id="ubx_facultyviz">
<div class='ubx-row'>
<div class="ubx-column--full">
<div id="ubx_intro">
${UBX_INTRO}
</div>
</div>
</div>
<div class='ubx-row ubx-row--relative'>
<div class="ubx-column">
<div id="ubx_main">
${UBX_BIOS}
${UBX_CHART}
</div>
</div>
<div id="ubx_roster"
class=${FULLWIDTH ? 'ubx-column--grow' : 'ubx-rowitem--roster' }
style="z-index: ${ubxzidx_roster}">
${UBX_ROSTER}
</div>
</div>
</div>`
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
refreshCampus = {
let coords = new Map([...starting_positions, ...Object.values(topic_positions)[topicslot]])
mutable topicabbr = [...topic_packs.values()][topicslot].abbr
svg_traffic.call(appendTravellers, [...coords.values()])
svg_packs.call(appendTopics, [...topic_packs.values()], topicslot)
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
school_packs = createPacks('school', schools_map, roster_map)
Insert cell
schools_map = new Map(SCHOOLS.map(obj => ([obj["abbr"], {...obj}])));
Insert cell
roster_map = new Map([...roster_json].map(obj => ([obj["id"], {...obj}])));
Insert cell
topics_map = new Map([...topics_json].map(obj => ([obj["full"], {...obj}])));
Insert cell
DISCRADIUS = 4
Insert cell
TOPICCOORDS = TOPICCOORDSMOBILE;
//TOPICCOORDS = (width > BREAKPOINT) ? TOPICCOORDSWIDE : TOPICCOORDSMOBILE;
Insert cell
Insert cell
topics_json = d3.json("https://urban.yale.edu/urbanex/terms/topics/all/list.json").then(d => { d.map(r => {r.full = r.full.replace("&amp;", "&")}); return d})
Insert cell
roster_json = d3.json("https://urban.yale.edu/urbanex/roster/full/list.json").then(d => { d.map(r => {r.topics = r.topics.replace("&amp;", "&").split(',')}); return d})
Insert cell
urbanschools = d3.json("https://urban.yale.edu/urbanex/terms/organizational_units/schools/list.json")
Insert cell
Insert cell
Insert cell
UBX_CHART = htl.html`<div id="ubx_chart_container"><div class="ubx_topo">${CAMPUSTOPO}</div><div id="ubx_legend">${CAMPUSLEGENDBOX}<p style="font-size: smaller">Click on a research area in the legend to highlight faculty.</p></div></div>`
Insert cell
UBX_BIOS = htl.html`<div id="ubx_biobox_container" style="z-index: ${ubxzidx_biobox}">${ROSTERBIOBOX}</div>`
Insert cell
ROSTERTRAFFICCONTROL = htl.html`<div class="ubx-form"> ${BUTTONPLAYPAUSE} <span>${trafficmessage}</span>${viewof topicSelectIdx}</div>`
Insert cell
Insert cell
UBX_ROSTER = htl.html`<div id="ubx_rosterer">${ROSTERTRAFFICCONTROL}<div class="ubx-pills">${ROSTERPILLBOX}</div></div>`
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
BUTTONPLAYPAUSE = htl.html`<button class="button--play-pause ${topicabbr}">${trafficsign == "go" ? "⏸" : "⏵"}</button>`
Insert cell
BUTTONPLAYPAUSE.onclick = function(){ directTraffic( ) };
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
viewof topicSelectIdx = Inputs.select(new Map([...topics_json].map((top, idx) => ([top["full"], idx]))), {value: topicslot});
Insert cell
viewof topicSelectIdx.oninput = function(e){ topicSelectIndexReset( e, this.value ) };
Insert cell
Insert cell
Insert cell
Insert cell
CSS_UBXMAIN = htl.html`
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Actor&family=Open+Sans+Condensed:wght@300&family=Open+Sans:wght@300&family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,600,1,200&display=swap" rel="stylesheet">

<style type="text/css">

/* STRUCTURE - POSITION and CONSTRAINTS */
#campus_root, #svg_root { width: ${CAMPUSWIDTH}px; height: ${MAINHEIGHT}px; }
#ubx_legend { display: block; position: relative; bottom: 180px; left: 25px }
#ubx_main { position: relative; }
#ubx_chart_container { max-width: 420px; max-height: 640px;}
#ubx_biobox_container, .ubx-rowitem--roster { width: 100%; height: 640px; max-width: 420px; max-height: 640px; position: absolute; top: 0; left: 0; background-color: white;}
#biobox_root { max-width: 420px; max-height: 640px; height: 800px; min-height: 400px; position: relative;}


/* STRUCTURE - TOP */
#ubx_intro {
margin: 0 0 1.5em 0;
}
#campus_intro {
max-width: 85%;
background-color: #c3ddf8;
font-family: "YaleNew", Georgia, "Times New Roman", serif;
color: #0c4b78;
padding: 1em 1.25em !important;
border-radius: 1.75em;
}

/* STRUCTURE - ROSTER */
#ubx_roster { padding: 0 .5em;}
#roster_root { display: flex; flex-wrap: wrap; }

.ubx-row {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
width: 100%;
}

.ubx-row--relative {
position: relative;
}

.ubx-column {
display: flex;
flex-direction: column;
flex: 1
}

.ubx-column--grow {
display: flex;
flex-direction: column;
flex: 3 1 auto;
}

.ubx-column--full {
display: flex;
flex-direction: column;
flex-basis: 100%;
flex: 4
}

/* TOPICS and TOPIC TIMER */

${[...topic_packs.values()].map(
(d) => `@keyframes ${d.abbr}-timer {
from { stroke-dashoffset: ${circumference(d.r)};}
to { stroke-dashoffset: 0;}
}
`).join('')}

${[...topic_packs.values()].map(
(d) => `#${d.id}.topic-show circle {
transform: rotateZ(-90deg);
stroke: ${d.fill};
stroke-width: 3px;
stroke-dasharray: ${circumference(d.r +4)};
stroke-dashoffset: 0;
animation: ${d.abbr}-timer ${TRAFFICINTERVAL/1000}s linear;
}
`).join('')}

/* TRAFFIC */

/* assign topic colors to css var for select */
${[...topic_packs.values()].map(
(d) => `form.${ns} select:has(option[value="${d.cnt}"]:checked) { --topic-color: ${d.fill} }
`).join('')}

form.${ns} select, .${ns} select {
font-size: 1.25rem;
color: var(--topic-color);
}

form.${ns} {
margin-top: 4px;
}
@keyframes topics-timer--playpause {
from { stroke-dashoffset: ${circumference(20)};}
to { stroke-dashoffset: 0;}
}

@keyframes rotate--playpause {
0% { transform: rotate(0); }
100% { transform: rotate(360deg); }
}

.button--play-pause {
float: left;
padding: 0 2px 0 0;
background-color: white;
color: black;
text-align: center;
text-decoration: none;
margin: -0.25em 0.5em 0 0;
display: block;
font-size: 1.2em;
height: 1.2em;
width: 1.2em;
border: 3px solid transparent;
border-radius: 50%;
}

.ubx-form {
min-height: 92px;
}

.ubx-form::before {
content: "\200b"; /* unicode zero width space character */
display: block;
height: 0;
}

.ubx-form span {white-space: normal;}



/* DISC PACKS */

g.school-pack text {
font-size: .85em;
font-family: 'Open Sans Condensed', sans-serif;
font-weight: 200;
stroke: #707070;
}

g.topic-pack text
{
font-size: smaller;
font-family: Helvetica, Arial, 'Open Sans', sans-serif;
font-weight: 300;
}

g.topic-show {
display:inline;
}

.roster-rows-h3 {
width: 100%;
font-size: 1em;
font-weight: 300;
font-family: Helvetica, Arial, 'Open Sans', sans-serif;
line-height: 2;
}

.viz-introtext-h {
font-size: 32px;
font-weight: 300;
font-family: Helvetica, Arial, 'Open Sans', sans-serif;
line-height: 1.6;
color: #286dc0;
}

.viz-introtext-p {
font-size: 32px;
line-height: 1.2;
width: 100%;
max-width: 100%;
}

/* LEGEND */

.legend-rows-div {
display:flex; flex-wrap: wrap; flex-direction:row; justify-content: flex-start; align-content: space-between;
position: relative;
max-width: 200px;
/* max-width: 49%; for splits */
/*top: -150px; */
}

.legend-row-div {
flex-basis: 100%;
max-height: 100px;
font-size: smaller;
line-height: 1.5em;
font-family: Helvetica, Arial, 'Open Sans', sans-serif;
font-weight: 400;
}

.legend-row-disc {
display: inline-block;
vertical-align: top;
margin: 0 4px 0 0;
}

.legend-row-text {
display: inline-block;
max-width: 90%;
}

/* ROSTER */
.gardencell {
font-family: '${fontName}', sans-serif;
font-size: 14px;
text-align:center; line-height: 1.2;
display: flex; align-items: center; justify-content: center;
padding: .1em .12em; margin: .2em; border-radius: 18px; min-height: 2em;
}

.gardencell img {
width: auto;
height: 28px !important;
margin-left: 4px;
border-radius: 20px;
}


@keyframes present-yourself {
to {
opacity: 1;
transform: translate3d(0,0,0);
}
}

/* BIOBOXEN */

.material-symbols-outlined {
font-variation-settings: 'FILL' 1, 'wght' 600, 'GRAD' 200, 'opsz' 24;
}
.ubx-column .node-person {

-webkit-text-size-adjust: 100%;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-webkit-tap-highlight-color: transparent;
font-weight: normal;
color: #222222;
font-family: "YaleNew", Georgia, "Times New Roman", serif;
font-size: 18px;
line-height: 26px;
box-sizing: inherit;
outline: none;
position: absolute;
top:0;
left:0;
width: 80%;
margin: 0 20px 40px;
text-align: center;

}

.ubx-column .node-person .close_me {
position: absolute;
width: 38px;
height: 38px;
top: 6px;
left: 4px;
color: white;
cursor: pointer;
padding-top: 7px;
border-radius: 38px;
background: radial-gradient(circle at center, rgba(99,99,99,1) 0%, rgba(99,99,99,.65) 55%, rgba(99,99,99,.5) 70%, transparent 100%);
}

.ubx-column .node-person .personheadshot {

-webkit-text-size-adjust: 100%;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-webkit-tap-highlight-color: transparent;
font-weight: normal;
color: #222222;
font-family: "YaleNew", Georgia, "Times New Roman", serif;
font-size: 18px;
line-height: 26px;
box-sizing: inherit;
text-align: center;
width: 100%;
max-width: 220px;
margin: 0;

}

.ubx-column .node-person .personheadshot img {

-webkit-text-size-adjust: 100%;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-webkit-tap-highlight-color: transparent;
font-weight: normal;
font-family: "YaleNew", Georgia, "Times New Roman", serif;
font-size: 18px;
text-align: center;
line-height: inherit;
color: #286dc0;
box-sizing: inherit;
max-width: 100%;
height: auto;
vertical-align: bottom;
border: 0;
border-radius: 25px;
}

.ubx-column .node-person .personname {

-webkit-text-size-adjust: 100%;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-webkit-tap-highlight-color: transparent;
font-weight: normal;
color: #222222;
font-size: 18px;
line-height: 26px;
box-sizing: inherit;
font-family: Helvetica, Arial, sans-serif;
display: table-cell;
background-color: #c3ddf8;
border-radius: 3em;
padding: 20px 20px;
text-align: center;
width: 100%;
margin: 0;

}

.ubx-column .node-person .body {

-webkit-text-size-adjust: 100%;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-webkit-tap-highlight-color: transparent;
font-weight: normal;
color: #222222;
font-family: "YaleNew", Georgia, "Times New Roman", serif;
box-sizing: inherit;
width: 100%;
margin: 0;
font-size: 16px;
line-height: 22px;
background-color: #c3ddf8;
border-radius: 1.75em;
padding: 20px;
text-align: left;

}

.ubx-column .node-person .body p {

-webkit-text-size-adjust: 100%;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-webkit-tap-highlight-color: transparent;
font-weight: normal;
color: #222222;
font-family: "YaleNew", Georgia, "Times New Roman", serif;
font-size: 16px;
line-height: 22px;
text-align: left;
box-sizing: inherit;
margin: 0;
padding: 0;
margin-bottom: 1em;

}

.ubx-column .node-person .body .biolink {

-webkit-text-size-adjust: 100%;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-webkit-tap-highlight-color: transparent;
font-weight: normal;
color: #222222;
font-family: "YaleNew", Georgia, "Times New Roman", serif;
font-size: 16px;
line-height: 22px;
box-sizing: inherit;
text-align: left !important;
width: 100%;
margin: 0;

}

.ubx-column .node-person .body .biolink .arrowbutton.square {

-webkit-text-size-adjust: 100%;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-webkit-tap-highlight-color: transparent;
font-weight: normal;
text-align: left !important;
box-sizing: inherit;
outline: none;
background: none;
border: 1px solid #4a4a4a;
color: #4a4a4a !important;
transition: none;
font-family: Helvetica, Arial, sans-serif !important;
font-size: 14px !important;
text-decoration: none !important;
margin: 0 5px;
white-space: nowrap;
line-height: 30px !important;
background-color: #c3ddf8 !important;
border-radius: 0;
padding: 4px 0 4px 12px;

}

.ubx-column .node-person .biolink .arrowbutton.square img {
-webkit-text-size-adjust: 100%;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-webkit-tap-highlight-color: transparent;
font-weight: normal;
text-align: left !important;
color: #4a4a4a !important;
font-family: Helvetica, Arial, sans-serif !important;
font-size: 14px !important;
white-space: nowrap;
line-height: 30px !important;
box-sizing: inherit;
max-width: 100%;
height: auto;
vertical-align: bottom;
border: 0;
width: 14px;
position: relative;
top: -16px;
right: -1px;
margin-left: 3px;
}
@media screen and (max-width: 420px) {

#campus_intro {
max-width: 95%;
}

.viz-introtext-h {
font-size: 28px;
}

.viz-introtext-p {
font-size: 28px;
}

.legend-rows-div { gap: 4px 15% }

.legend-row-div {
flex-basis: 100%;
font-size: smaller;
font-family: Helvetica, Arial, 'Open Sans', sans-serif;
font-weight: 300;
}

.legend-row-text {
display: inline-block;
max-width: 100%;
}



}
</style>
`
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
viewof fontName = Inputs.select(["Actor", "Work Sans", "Geologica", "Gothic A1", "Atkinson Hyperlegible", "Krub"], {label: "Pill Fontname"})
Insert cell
viewof include_topic_contours = Inputs.toggle({label: "Topics in contours?", value: true})
//client option
Insert cell
viewof solidback = Inputs.radio(["solid", "semi"], {value: "solid"})
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more