mirror of
https://github.com/jackyzha0/quartz.git
synced 2026-02-03 22:15:42 -06:00
Merge 8c8a7ac903 into ec00a40aef
This commit is contained in:
commit
71e42c52aa
@ -41,7 +41,11 @@ export const defaultContentPageLayout: PageLayout = {
|
||||
Component.Explorer(),
|
||||
],
|
||||
right: [
|
||||
Component.Graph(),
|
||||
Component.Graph({
|
||||
localGraph: {
|
||||
defaultZoom: 2,
|
||||
},
|
||||
}),
|
||||
Component.DesktopOnly(Component.TableOfContents()),
|
||||
Component.Backlinks(),
|
||||
],
|
||||
|
||||
@ -19,6 +19,7 @@ export interface D3Config {
|
||||
showTags: boolean
|
||||
focusOnHover?: boolean
|
||||
enableRadial?: boolean
|
||||
defaultZoom?: number
|
||||
}
|
||||
|
||||
interface GraphOptions {
|
||||
@ -41,6 +42,7 @@ const defaultOptions: GraphOptions = {
|
||||
removeTags: [],
|
||||
focusOnHover: false,
|
||||
enableRadial: false,
|
||||
defaultZoom: 1,
|
||||
},
|
||||
globalGraph: {
|
||||
drag: true,
|
||||
@ -56,6 +58,7 @@ const defaultOptions: GraphOptions = {
|
||||
removeTags: [],
|
||||
focusOnHover: true,
|
||||
enableRadial: true,
|
||||
defaultZoom: 1,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -87,6 +87,7 @@ async function renderGraph(graph: HTMLElement, fullSlug: FullSlug) {
|
||||
showTags,
|
||||
focusOnHover,
|
||||
enableRadial,
|
||||
defaultZoom,
|
||||
} = JSON.parse(graph.dataset["cfg"]!) as D3Config
|
||||
|
||||
const data: Map<SimpleSlug, ContentDetails> = new Map(
|
||||
@ -497,30 +498,41 @@ async function renderGraph(graph: HTMLElement, fullSlug: FullSlug) {
|
||||
}
|
||||
|
||||
if (enableZoom) {
|
||||
select<HTMLCanvasElement, NodeData>(app.canvas).call(
|
||||
zoom<HTMLCanvasElement, NodeData>()
|
||||
.extent([
|
||||
[0, 0],
|
||||
[width, height],
|
||||
])
|
||||
.scaleExtent([0.25, 4])
|
||||
.on("zoom", ({ transform }) => {
|
||||
currentTransform = transform
|
||||
stage.scale.set(transform.k, transform.k)
|
||||
stage.position.set(transform.x, transform.y)
|
||||
const zoomBehavior = zoom<HTMLCanvasElement, NodeData>()
|
||||
.extent([
|
||||
[0, 0],
|
||||
[width, height],
|
||||
])
|
||||
.scaleExtent([0.25, 4])
|
||||
.on("zoom", ({ transform }) => {
|
||||
currentTransform = transform
|
||||
stage.scale.set(transform.k, transform.k)
|
||||
stage.position.set(transform.x, transform.y)
|
||||
|
||||
// zoom adjusts opacity of labels too
|
||||
const scale = transform.k * opacityScale
|
||||
let scaleOpacity = Math.max((scale - 1) / 3.75, 0)
|
||||
const activeNodes = nodeRenderData.filter((n) => n.active).flatMap((n) => n.label)
|
||||
// zoom adjusts opacity of labels too
|
||||
const scale = transform.k * opacityScale
|
||||
let scaleOpacity = Math.max((scale - 1) / 3.75, 0)
|
||||
const activeNodes = nodeRenderData.filter((n) => n.active).flatMap((n) => n.label)
|
||||
|
||||
for (const label of labelsContainer.children) {
|
||||
if (!activeNodes.includes(label)) {
|
||||
label.alpha = scaleOpacity
|
||||
}
|
||||
for (const label of labelsContainer.children) {
|
||||
if (!activeNodes.includes(label)) {
|
||||
label.alpha = scaleOpacity
|
||||
}
|
||||
}),
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
const canvas = select<HTMLCanvasElement, NodeData>(app.canvas)
|
||||
canvas.call(zoomBehavior)
|
||||
|
||||
// Apply default zoom (defaults to 1 if not provided)
|
||||
const zoomLevel = defaultZoom ?? 1
|
||||
if (zoomLevel !== 1) {
|
||||
const defaultTransform = zoomIdentity
|
||||
.translate(width / 2, height / 2)
|
||||
.scale(zoomLevel)
|
||||
.translate(-width / 2, -height / 2)
|
||||
canvas.call(zoomBehavior.transform, defaultTransform)
|
||||
}
|
||||
}
|
||||
|
||||
let stopAnimation = false
|
||||
|
||||
91
quartz/components/scripts/graph.test.ts
Normal file
91
quartz/components/scripts/graph.test.ts
Normal file
@ -0,0 +1,91 @@
|
||||
import test, { describe } from "node:test"
|
||||
import assert from "node:assert"
|
||||
import { zoomIdentity } from "d3"
|
||||
|
||||
describe("graph", () => {
|
||||
describe("defaultZoom", () => {
|
||||
test("should create identity transform when not specified", () => {
|
||||
const transform = zoomIdentity
|
||||
assert.strictEqual(transform.k, 1)
|
||||
assert.strictEqual(transform.x, 0)
|
||||
assert.strictEqual(transform.y, 0)
|
||||
})
|
||||
|
||||
test("should scale correctly when defaultZoom is 2", () => {
|
||||
const width = 400
|
||||
const height = 300
|
||||
const defaultZoom = 2
|
||||
|
||||
const transform = zoomIdentity
|
||||
.translate(width / 2, height / 2)
|
||||
.scale(defaultZoom)
|
||||
.translate(-width / 2, -height / 2)
|
||||
|
||||
assert.strictEqual(transform.k, defaultZoom)
|
||||
assert.strictEqual(transform.x, -200)
|
||||
assert.strictEqual(transform.y, -150)
|
||||
})
|
||||
|
||||
test("should produce identity-like transform when defaultZoom is 1", () => {
|
||||
const width = 400
|
||||
const height = 300
|
||||
const defaultZoom = 1
|
||||
|
||||
const transform = zoomIdentity
|
||||
.translate(width / 2, height / 2)
|
||||
.scale(defaultZoom)
|
||||
.translate(-width / 2, -height / 2)
|
||||
|
||||
assert.strictEqual(transform.k, 1)
|
||||
assert.strictEqual(transform.x, 0)
|
||||
assert.strictEqual(transform.y, 0)
|
||||
})
|
||||
|
||||
test("should zoom out when defaultZoom is 0.5", () => {
|
||||
const width = 400
|
||||
const height = 300
|
||||
const defaultZoom = 0.5
|
||||
|
||||
const transform = zoomIdentity
|
||||
.translate(width / 2, height / 2)
|
||||
.scale(defaultZoom)
|
||||
.translate(-width / 2, -height / 2)
|
||||
|
||||
assert.strictEqual(transform.k, 0.5)
|
||||
assert.strictEqual(transform.x, 100)
|
||||
assert.strictEqual(transform.y, 75)
|
||||
})
|
||||
|
||||
test("should keep center point stationary after zoom", () => {
|
||||
const width = 400
|
||||
const height = 300
|
||||
const defaultZoom = 2
|
||||
|
||||
const transform = zoomIdentity
|
||||
.translate(width / 2, height / 2)
|
||||
.scale(defaultZoom)
|
||||
.translate(-width / 2, -height / 2)
|
||||
|
||||
const centerX = width / 2
|
||||
const centerY = height / 2
|
||||
const [newX, newY] = transform.apply([centerX, centerY])
|
||||
|
||||
assert.strictEqual(newX, centerX)
|
||||
assert.strictEqual(newY, centerY)
|
||||
})
|
||||
|
||||
test("should default to 1 when defaultZoom is undefined", () => {
|
||||
const defaultZoom: number | undefined = undefined
|
||||
const zoomLevel = defaultZoom ?? 1
|
||||
|
||||
assert.strictEqual(zoomLevel, 1)
|
||||
})
|
||||
|
||||
test("should use provided value when defaultZoom is defined", () => {
|
||||
const defaultZoom: number | undefined = 2.5
|
||||
const zoomLevel = defaultZoom ?? 1
|
||||
|
||||
assert.strictEqual(zoomLevel, 2.5)
|
||||
})
|
||||
})
|
||||
})
|
||||
Loading…
Reference in New Issue
Block a user