Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesdabbs committed Nov 12, 2023
1 parent 22211ae commit c6b3841
Show file tree
Hide file tree
Showing 10 changed files with 817 additions and 86 deletions.
3 changes: 3 additions & 0 deletions packages/viewer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@
"@pi-base/core": "workspace:*",
"@sentry/browser": "^7.75.1",
"bootstrap": "^4.6.2",
"d3": "^7.8.5",
"debug": "^4.3.4",
"fromnow": "^3.0.1",
"fuse.js": "^6.6.2",
"hast-to-hyperscript": "^10.0.3",
"hyperscript": "^2.0.2",
"jquery": "1.12.4",
"katex": "^0.16.9",
"rehype-katex": "^6.0.3",
"remark-rehype": "^10.1.0",
"unified": "^10.1.2",
Expand All @@ -37,6 +39,7 @@
"@sveltejs/kit": "^1.27.1",
"@sveltejs/vite-plugin-svelte": "^2.4.6",
"@tsconfig/svelte": "^3.0.0",
"@types/d3": "^7.4.3",
"@types/debug": "^4.1.10",
"@types/hyperscript": "0.0.6",
"@types/katex": "^0.16.5",
Expand Down
11 changes: 11 additions & 0 deletions packages/viewer/public/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,14 @@
.description {
margin-bottom: 1rem;
}

.links line {
stroke: #999;
stroke-opacity: 0.6;
}

.nodes circle {
stroke: #fff;
stroke-width: 1.5px;
}

30 changes: 15 additions & 15 deletions packages/viewer/src/app.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,25 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />

<title>π-Base</title>
<title>π-Base</title>

<meta name="author" content="James Dabbs" />
<meta name="description"
content="A community database of topological theorems and spaces, with powerful search and automated proof deduction." />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="π-Base" />
<meta property="og:url" name="twitter:url" content="https://topology.pi-base.org" />
<meta property="og:title" name="twitter:title" content="π-Base" />
<meta property="og:description" name="twitter:description"
content="A community database of topological theorems and spaces, with powerful search and automated proof deduction." />
<meta property="og:image" content="%sveltekit.assets%/pi-base.png" />
<meta name="twitter:site" content="π-Base" />
<meta name="twitter:creator" content="@jamesdabbs" />
<meta name="author" content="James Dabbs" />
<meta name="description"
content="A community database of topological theorems and spaces, with powerful search and automated proof deduction." />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="π-Base" />
<meta property="og:url" name="twitter:url" content="https://topology.pi-base.org" />
<meta property="og:title" name="twitter:title" content="π-Base" />
<meta property="og:description" name="twitter:description"
content="A community database of topological theorems and spaces, with powerful search and automated proof deduction." />
<meta property="og:image" content="%sveltekit.assets%/pi-base.png" />
<meta name="twitter:site" content="π-Base" />
<meta name="twitter:creator" content="@jamesdabbs" />

<link rel="icon" href="%sveltekit.assets%/favicon.ico" />

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css" integrity="sha384-Xi8rHCmBmhbuyyhbI88391ZKP2dmfnOl4rT9ZfRI7mLTdk1wblIUnrIq35nqwEvC" crossorigin="anonymous">
<link rel='stylesheet' href='/global.css'>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css" integrity="sha384-Xi8rHCmBmhbuyyhbI88391ZKP2dmfnOl4rT9ZfRI7mLTdk1wblIUnrIq35nqwEvC" crossorigin="anonymous">
<link rel='stylesheet' href='/global.css'>

%sveltekit.head%
</head>
Expand Down
9 changes: 6 additions & 3 deletions packages/viewer/src/components/Theorems/Table.svelte
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
<script lang="ts">
import type { Theorem } from '@/models'
import type { Property, Theorem } from '@/models'
import { Formula, Link } from '../Shared'
import type { Readable } from 'svelte/store'
export let theorems: Theorem[] = []
export let small = false
export let selected: Readable<Theorem | Property> | undefined = undefined
</script>

<table class="table">
<table class="table" class:table-sm={small}>
<thead>
<tr>
<th>Id</th>
Expand All @@ -15,7 +18,7 @@
</thead>
<tbody>
{#each theorems as theorem (theorem.id)}
<tr>
<tr class:table-warning={$selected === theorem}>
<td>
<Link.Theorem {theorem} />
</td>
Expand Down
229 changes: 229 additions & 0 deletions packages/viewer/src/components/Traits/Graph.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
<script lang="ts">
import { onMount } from 'svelte'
import * as d3 from 'd3'
import type { Property, Trait, Theorem } from '@/models'
import { formula } from '@pi-base/core'
import * as katex from 'katex'
import type { Writable } from 'svelte/store'
export let selected: Writable<Property | Theorem>
export let property: Property
export let traits: [Property, Trait][]
export let theorems: Theorem[]
function renderLatex(s: string) {
return s.replaceAll(/\$[^$]+\$/g, p => {
return (katex as any).default.renderToString(p.replaceAll('$', ''))
})
}
type DragEvent = d3.D3DragEvent<HTMLElement, unknown, Node>
type Node = d3.SimulationNodeDatum & {
property: Property
trait?: Trait
degree: number
pinned?: { x?: number; y?: number }
}
type Link = d3.SimulationLinkDatum<Node> & { theorem: Theorem }
let nodes: Node[]
let links: Link[]
let el: SVGSVGElement
const width = 600
const height = 600
const bound = 200
const textWidth = 500
$: {
// Build graph
// - one node per property
// - theorems correspond to edges linking "when" and "then" ()
const inodes: Record<string, Node> = {}
links = []
for (const theorem of theorems) {
for (const a of formula.properties(theorem.when)) {
inodes[a.id] ||= { property: a, degree: 0 }
inodes[a.id].degree++
for (const c of formula.properties(theorem.then)) {
inodes[c.id] ||= { property: c, degree: 0 }
inodes[c.id].degree++
links.push({
source: a.id.toString(),
target: c.id.toString(),
theorem,
})
}
}
}
for (const [property, trait] of traits) {
inodes[property.id] ||= { property, degree: 0 }
inodes[property.id].trait = trait
inodes[property.id].fx = -1 * bound
inodes[property.id].pinned = { x: -1 * bound }
}
inodes[property.id].fx = bound
inodes[property.id].fy = 1
inodes[property.id].pinned = { x: bound, y: 1 }
nodes = Object.values(inodes)
}
onMount(() => {
const color = d3.scaleOrdinal(d3.schemeTableau10)
const simulation = d3
.forceSimulation(nodes)
.force(
'link',
d3.forceLink<Node, Link>(links).id(d => d.property.id.toString()),
)
.force(
'charge',
d3.forceManyBody<Node>().strength(d => -100 * (d.pinned ? 10 : 1)),
)
.force(
'x',
d3.forceX().strength(d => {
const x = d.x || 0
return Math.min((x / bound) * (x / bound), 1)
}),
)
const svg = d3
.select(el)
.attr('width', width)
.attr('height', height)
.attr('viewBox', [-width / 2, -height / 2, width, height])
.attr('style', 'max-width: 100%; width: 100%; height: 100%;')
const text = svg
.append('g')
.attr('class', 'labels')
.selectAll('foreignObject')
.data(nodes)
.enter()
.append('foreignObject')
.attr(
'requiredFeatures',
'http://www.w3.org/TR/SVG11/feature#Extensibility',
)
.attr('width', `${textWidth}px`)
.attr('height', '2em')
const link = svg
.append('g')
.attr('stroke', '#777')
.attr('stroke-opacity', 0.6)
.selectAll('path')
.data(links)
.join('path')
.attr('stroke-width', 2)
.attr('marker-mid', 'url(#arrowhead)')
.on('mouseover', function () {
const datum = d3.select(this).datum() as { theorem: Theorem }
if (datum.theorem) {
$selected = datum.theorem
}
})
text
.append('xhtml:div')
.html(d => (d.degree > 2 || d.pinned ? renderLatex(d.property.name) : ''))
.style('width', '100%')
.style('text-align', 'center')
const node = svg
.append('g')
.selectAll('circle')
.data(nodes)
.enter()
.append('circle')
.attr('stroke', '#888')
.attr('stroke-width', d => (d.pinned ? 3 : 1.5))
.attr('r', d => {
if (d.pinned) {
return 10
} else if (d.degree > 2) {
return 8
} else {
return 5
}
})
.attr('fill', d => (d.pinned || d.degree > 2 ? color('1') : color('2')))
.on('mouseover', function () {
const datum = d3.select(this).datum() as { property: Property }
if (datum.property) {
$selected = datum.property
}
})
node.append('title').text(d => d.property.name)
node.call(
d3
.drag<any, Node, unknown>()
.on('start', dragstarted)
.on('drag', dragged)
.on('end', dragended),
)
simulation.on('tick', () => {
link.attr('d', ({ source, target }: Link) => {
const { x: x1 = 0, y: y1 = 0 } = source as Node
const { x: x2 = 0, y: y2 = 0 } = target as Node
const mx = (x2 - x1) / 2 + x1
const my = (y2 - y1) / 2 + y1
return `M${x1},${y1}L${mx},${my}L${x2},${y2}`
})
node.attr('cx', (d: Node) => d.x!).attr('cy', (d: Node) => d.y!)
text
.attr('x', (d: Node) => d.x! - textWidth / 2)
.attr('y', (d: Node) => d.y! + 8)
})
function dragstarted({ active, subject }: DragEvent) {
if (!active) simulation.alphaTarget(0.3).restart()
subject.fx = subject.pinned?.x || subject.x
subject.fy = subject.pinned?.y || subject.y
}
function dragged({ subject, x, y }: DragEvent) {
subject.fx = subject.pinned?.x || x
subject.fy = subject.pinned?.y || y
}
function dragended({ active, subject }: DragEvent) {
if (!active) simulation.alphaTarget(0)
subject.fx = subject.pinned?.x
subject.fy = subject.pinned?.y
}
})
</script>

<svg xmlns="http://www.w3.org/2000/svg" bind:this={el}>
<defs>
<marker
id="arrowhead"
markerWidth="3"
markerHeight="3"
refX="0"
refY="1.5"
orient="auto"
>
<polygon points="0,0 3,1.5 0,3" fill="#888" />
</marker>
</defs>
</svg>
28 changes: 21 additions & 7 deletions packages/viewer/src/components/Traits/Proof.svelte
Original file line number Diff line number Diff line change
@@ -1,28 +1,43 @@
<script lang="ts">
import { writable } from 'svelte/store'
import { Link } from '../Shared'
import { Table as Theorems } from '../Theorems'
import Graph from './Graph.svelte'
import Value from './Value.svelte'
import type { Property, Space, Theorem, Trait } from '@/models'
export let space: Space
export let property: Property
export let theorems: Theorem[]
export let traits: [Property, Trait][]
const selected = writable<Property | Theorem>()
</script>

Automatically deduced from the following:

<div class="row">
<div class="col">
<h5>Properties</h5>
<table class="table">
<div class="col-7">
<Graph {property} {traits} {theorems} {selected} />
</div>
<div class="col-5">
<h5>Assumptions</h5>
<table class="table table-sm">
<thead>
<tr>
<th>Id</th>
<th>Property</th>
<th>Value</th>
</tr>
</thead>
<tbody>
{#each traits as [property, trait] (property.id)}
<tr>
<tr class:table-warning={$selected === property}>
<td>
<Link.Property {property}>
{property.id}
</Link.Property>
</td>
<td>
<Link.Property {property} />
</td>
Expand All @@ -35,9 +50,8 @@ Automatically deduced from the following:
{/each}
</tbody>
</table>
</div>
<div class="col">

<h5>Theorems</h5>
<Theorems {theorems} />
<Theorems {theorems} small={true} {selected} />
</div>
</div>
Loading

0 comments on commit c6b3841

Please sign in to comment.