Skip to content

Commit

Permalink
make people a variable size based on how many people know them
Browse files Browse the repository at this point in the history
also show who knows them in ProfileCard
also draw lines only until the edge of a node
  • Loading branch information
mrkvon committed Jul 21, 2021
1 parent cdba7c8 commit 84f2f05
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 53 deletions.
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@
## TODO

- [x] add people to history of browser (will allow browsing)
- [ ] make people a variable size based on how many people know them
- [x] make people a variable size based on how many people know them
- [ ] show clearly what are the directions of :knows
- [ ] show also who knows this person
- [x] show also who knows this person
- [ ] login for different pod providers
- [ ] faster (parallel) crawling
- [ ] search people
- [ ] highlight also people who know the person
- [ ] highlight people whose button is crawled in PersonList
- [ ] add custom starting point for crawling
9 changes: 9 additions & 0 deletions src/components/DataContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export type Person = {
photo: string
status: 'success' | 'error' | 'pending'
knows: Set<IriString>
known?: Set<IriString>
}

const DataContainer = ({ children }: Props) => {
Expand Down Expand Up @@ -42,6 +43,14 @@ const DataContainer = ({ children }: Props) => {
return BFSFriends([timbl, ...(info?.isLoggedIn ? [me] : [])], setPeople)
}, [info])

Object.values(people).forEach(({ uri, knows }) => {
knows.forEach(k => {
const person = people[k]
person.known = person.known ?? new Set()
person.known.add(uri)
})
})

return (
<PeopleContext.Provider value={people}>{children}</PeopleContext.Provider>
)
Expand Down
21 changes: 19 additions & 2 deletions src/components/PersonCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import { Person } from './DataContainer'
interface Props {
person: Person
knows: Person[]
known: Person[]
onSelectPerson: (uri: string) => void
}

const Statement = ({ person, knows, onSelectPerson }: Props) => {
const PersonCard = ({ person, knows, known, onSelectPerson }: Props) => {
return (
<div
style={{
Expand Down Expand Up @@ -54,11 +55,27 @@ const Statement = ({ person, knows, onSelectPerson }: Props) => {
))}
</ul>
</section>
<header className="card-header">
<p className="card-header-title">known by: {known.length}</p>
</header>
<section className="card-content">
<ul className="buttons are-small">
{known.map(friend => (
<li
onClick={() => onSelectPerson(friend.uri)}
key={friend.uri}
className="button is-link"
>
{friend.name}
</li>
))}
</ul>
</section>
</div>
</div>
</div>
</div>
)
}

export default Statement
export default PersonCard
50 changes: 32 additions & 18 deletions src/components/Visualization.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,22 @@ const Visualization: React.FC<Props> = ({
context.clearRect(-offset[0], -offset[1], width, height)
drawGrid(context, grid, width, height, offset)
graph.links.forEach(link => {
// we're counting a unit vector to make links that don't overlap nodes
// source point
const s = [link.source.x, link.source.y]
// target point
const t = [link.target.x, link.target.y]
// vector
const v = numeric.sub(t, s)
// vector size
const size = Math.sqrt(v[0] ** 2 + v[1] ** 2)
// unit vector
const i = numeric.div(v, size)
drawLine(
context,
[link.source.x, link.source.y],
[link.target.x, link.target.y],
// links don't overlap circles
numeric.add(s, numeric.mul(i, link.source.r)) as Vector,
numeric.sub(t, numeric.mul(i, link.target.r)) as Vector,
{
strokeStyle: 'white',
lineWidth: 0.5,
Expand All @@ -70,41 +82,43 @@ const Visualization: React.FC<Props> = ({
const rest = graph.nodes.filter(({ style }) => !style)

// draw all the nodes which are not special
rest.forEach(({ x, y }) =>
drawCircle(context, [x, y], 10, { fillStyle: '#fff8' }),
rest.forEach(({ x, y, r }) =>
drawCircle(context, [x, y], r, { fillStyle: '#fff8' }),
)

// draw errored nodes
errored.forEach(({ x, y }) =>
drawCircle(context, [x, y], 10, { fillStyle: erroredColor }),
errored.forEach(({ x, y, r }) =>
drawCircle(context, [x, y], r, { fillStyle: erroredColor }),
)

// draw successed nodes
successed.forEach(({ x, y }) =>
drawCircle(context, [x, y], 10, { fillStyle: successedColor }),
successed.forEach(({ x, y, r }) =>
drawCircle(context, [x, y], r, { fillStyle: successedColor }),
)

// draw text of all the above nodes
;[...errored, ...successed, ...rest].forEach(({ x, y, label }) =>
drawText(context, [x + 15, y], label, { fillStyle: '#fff4' }),
;[...errored, ...successed, ...rest].forEach(({ x, y, r, label }) =>
drawText(context, [x + r + 5, y], label, { fillStyle: '#fff4' }),
)

// draw accented nodes
accented.forEach(({ x, y }) =>
drawCircle(context, [x, y], 10, { fillStyle: accentedColor }),
accented.forEach(({ x, y, r }) =>
drawCircle(context, [x, y], r, { fillStyle: accentedColor }),
)

accented.forEach(({ x, y, label }) =>
drawText(context, [x + 15, y], label, { fillStyle: accentedColor }),
accented.forEach(({ x, y, r, label }) =>
drawText(context, [x + r + 5, y], label, {
fillStyle: accentedColor,
}),
)

// draw focused nodes
focused.forEach(({ x, y }) =>
drawCircle(context, [x, y], 10, { fillStyle: focusedColor }),
focused.forEach(({ x, y, r }) =>
drawCircle(context, [x, y], r, { fillStyle: focusedColor }),
)

focused.forEach(({ x, y, label }) =>
drawText(context, [x + 15, y], label, { fillStyle: focusedColor }),
focused.forEach(({ x, y, r, label }) =>
drawText(context, [x + r + 5, y], label, { fillStyle: focusedColor }),
)

return () => context.restore()
Expand Down
39 changes: 26 additions & 13 deletions src/components/VisualizationContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ const transformLayout = (
const transformedNodesDict = Object.fromEntries(
graph.nodes.map(node => {
const [x, y] = transform(matrix, [node.x, node.y])
const r = matrix[0][0] * node.r
const status = people[node.uri]?.status ?? ''
const style =
status === 'success' ? 'success' : status === 'error' ? 'error' : ''
Expand All @@ -86,9 +87,10 @@ const transformLayout = (
...node,
x,
y,
r,
style,
label: people[node.uri]?.name ?? '',
} as VisualizationNode,
},
]
}),
)
Expand Down Expand Up @@ -126,6 +128,12 @@ const transformLayout = (
return { nodes: Object.values(transformedNodesDict), links }
}

function nodeRadius(person: Person) {
let count = person.known?.size ?? 0
count = count < 1 ? 1 : count
return count ** 0.42 * 5
}

const selectNodeDependencies = (
selectedNodeUri: string | undefined,
graph: PeopleGraph,
Expand Down Expand Up @@ -178,16 +186,13 @@ const VisualizationContainer: React.FC<RouteComponentProps> = ({

// when graph changes, update simulation
useEffect(() => {
const prunedOrFullGraph = people

const nodes = Object.values(prunedOrFullGraph).map(
({ name: label, uri }) => ({
label,
uri,
}),
)
const nodes = Object.values(people).map(node => ({
label: node.name,
uri: node.uri,
r: nodeRadius(node),
}))

const links = Object.values(prunedOrFullGraph).reduce(
const links = Object.values(people).reduce(
(nodes, { uri: source, knows }) => {
knows.forEach(target => nodes.push({ source, target }))
return nodes
Expand Down Expand Up @@ -233,12 +238,15 @@ const VisualizationContainer: React.FC<RouteComponentProps> = ({

const grid = transformGrid(matrix, basicGrid)

let person, knows
let person, knows, known

if (selectedNode) {
person = people[selectedNode]
if (person) {
knows = Array.from(person.knows).map(f => people[f])
if (person.known) {
known = Array.from(person.known).map(f => people[f])
}
}
}

Expand All @@ -260,8 +268,13 @@ const VisualizationContainer: React.FC<RouteComponentProps> = ({
</title>
</Helmet>

{person && knows && (
<PersonCard person={person} knows={knows} onSelectPerson={selectNode} />
{person && knows && known && (
<PersonCard
person={person}
knows={knows}
known={known}
onSelectPerson={selectNode}
/>
)}
</>
)
Expand Down
31 changes: 16 additions & 15 deletions src/simulation/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { Coords, Uri, SimulationNode, SimulationLink, Node } from './types'

interface SimulationNodeExt extends SimulationNodeDatum {
uri: Uri
r: number
}

export type SimulationLinkExt = SimulationLinkDatum<SimulationNodeExt>
Expand All @@ -36,7 +37,10 @@ export default class Simulation {
.force('charge', forceManyBody().strength(-150).distanceMax(500))
.force('gravityX', forceX(0).strength(0.01))
.force('gravityY', forceY(0).strength(0.01))
.force('collide', forceCollide(15))
.force(
'collide',
forceCollide(({ r }: SimulationNodeExt) => r + 5),
)
.force('center', forceCenter(0, 0))
.stop()

Expand Down Expand Up @@ -81,20 +85,17 @@ export default class Simulation {

update = ({ nodes, links }: { nodes: Node[]; links: SimulationLink[] }) => {
this.simulation.stop()
// combine current visualization and
// combine current nodes and the old nodes
const thisNodeDict: { [uri: string]: SimulationNodeExt } =
Object.fromEntries(this.nodes.map(node => [node.uri, node]))
const nodeDict: { [uri: string]: SimulationNodeExt } = Object.fromEntries(
nodes.map(node => [
node.uri,
{
...node,
x: Math.random() * 400,
y: Math.random() * 400,
},
]),
)
this.nodes = Object.values({ ...nodeDict, ...thisNodeDict })
const updatedNodes: SimulationNodeExt[] = nodes.map(node => ({
...node,
x: Math.random() * 400,
y: Math.random() * 400,
...thisNodeDict[node.uri],
r: node.r,
}))
this.nodes = updatedNodes
this.links = links.map(link => ({ ...link })) as SimulationLinkExt[]

this.simulation.nodes(this.nodes)
Expand All @@ -105,9 +106,9 @@ export default class Simulation {
>
).links(this.links)

this.simulation.alpha(0.5).restart()
this.simulation.alpha(1).restart()
}

selectNode = ({ x, y }: Coords) =>
this.simulation.find(x, y, 32) as SimulationNodeExt
this.simulation.find(x, y, 40) as SimulationNodeExt
}
5 changes: 2 additions & 3 deletions src/simulation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,15 @@ export interface DependencyExtended {
export interface Node {
label: string
uri: Uri
r: number
}

export interface Coords {
x: number
y: number
}

export interface SimulationNode extends Node, Coords {
radius?: number
}
export interface SimulationNode extends Node, Coords {}

export interface SimulationLink {
source: Uri
Expand Down

0 comments on commit 84f2f05

Please sign in to comment.