From b4dfb5c78c9dbee9cebc2fdc79b8b0d9b0bd231c Mon Sep 17 00:00:00 2001 From: Wlad Meixner Date: Fri, 22 Sep 2023 15:37:18 +0200 Subject: [PATCH] wip: refactor layout and rendering path --- src/lib/actions/clickOutside.ts | 28 + src/lib/actions/portal.ts | 73 +++ src/lib/components/BasicGraph.svelte | 49 +- src/lib/components/Card.svelte | 2 +- src/lib/components/CodeEditor.svelte | 2 +- src/lib/components/Dialog.svelte | 6 +- src/lib/components/DropZone.svelte | 2 +- src/lib/components/Dropdown.svelte | 37 +- src/lib/components/DropdownSelect.svelte | 12 +- src/lib/components/FilterSidebar.svelte | 40 +- src/lib/components/TableSelection.svelte | 5 +- src/lib/components/base/Divider.svelte | 2 +- src/lib/components/graph/Graph2D.svelte | 157 +++++ src/lib/components/graph/Minimal.svelte | 2 +- src/lib/components/graph/PlaneGraph.svelte | 52 +- src/lib/components/graph/types.ts | 6 +- src/lib/rendering/AxisRenderer.ts | 457 +++++++------- src/lib/rendering/GraphRenderer.ts | 15 +- src/lib/rendering/Minimap.ts | 579 +++++++++--------- src/lib/rendering/PlaneRenderer.ts | 567 +++++++++-------- .../rendering/geometry/DataPlaneGeometry.ts | 65 +- src/lib/rendering/textures/TextTexture.ts | 61 ++ src/lib/store/SettingsStore.ts | 48 +- src/lib/store/dataStore/filterActions.ts | 93 +-- src/lib/store/dataStore/loadActions.ts | 28 +- src/lib/store/filterStore/graphs/plane.ts | 17 +- src/routes/+layout.svelte | 21 +- src/routes/graph/+page.svelte | 7 - 28 files changed, 1477 insertions(+), 956 deletions(-) create mode 100644 src/lib/actions/clickOutside.ts create mode 100644 src/lib/actions/portal.ts create mode 100644 src/lib/components/graph/Graph2D.svelte create mode 100644 src/lib/rendering/textures/TextTexture.ts diff --git a/src/lib/actions/clickOutside.ts b/src/lib/actions/clickOutside.ts new file mode 100644 index 0000000..357ced1 --- /dev/null +++ b/src/lib/actions/clickOutside.ts @@ -0,0 +1,28 @@ +export type ActionClickOutsideOptions = { + onClickOutside: () => void; + whitelist?: HTMLElement[]; +}; + +export default (node: HTMLElement, options: ActionClickOutsideOptions) => { + let whitelist = options.whitelist?.filter((el) => el !== undefined) ?? []; + let onOutsideClick = options.onClickOutside; + const detectClick = (event: MouseEvent) => { + const target = event.target as Node; + if (!node.contains(target) && !whitelist.some((el) => el.isSameNode(target))) { + onOutsideClick(); + } + return; + }; + const listenerOptions = { passive: true, capture: true }; + document.addEventListener('click', detectClick, listenerOptions); + + return { + destroy() { + document.removeEventListener('click', detectClick, listenerOptions); + }, + update(params: ActionClickOutsideOptions) { + whitelist = params.whitelist?.filter((el) => el !== undefined) ?? []; + onOutsideClick = params.onClickOutside; + } + }; +}; diff --git a/src/lib/actions/portal.ts b/src/lib/actions/portal.ts new file mode 100644 index 0000000..041c4cb --- /dev/null +++ b/src/lib/actions/portal.ts @@ -0,0 +1,73 @@ +export const portal = (node: HTMLElement) => { + const target = document.querySelector('main'); + target?.appendChild(node).focus(); + + return { + destroy() { + if (target?.contains(node)) { + target?.removeChild(node); + } + } + }; +}; + +const findParentWithClass = (element: HTMLElement, className: string): HTMLElement | null => { + let el: HTMLElement | null = element; + while (el) { + if (el.classList && el.classList.contains(className)) { + return el; + } + el = el.parentElement; + } + + return null; +}; + +export const defaultPortalRootClass = 'portal-root'; + +export const relativePortal = (node: HTMLElement, rootClass = defaultPortalRootClass) => { + // position node relative to its parent + const parent = node.parentElement; + if (!parent) { + return portal(node); + } + + const componentBounds = node.getBoundingClientRect(); + const parentBounds = parent.getBoundingClientRect(); + + let left = parentBounds.left; + let top = parentBounds.top + parentBounds.height + 3; + + if (window.innerWidth < left + componentBounds.width) { + left = window.innerWidth - (componentBounds.width + 25); + } + + if (window.innerHeight < top + componentBounds.height) { + top = window.innerHeight - (componentBounds.height + 25); + } + + node.style.left = `${left}px`; + node.style.top = `${top}px`; + + // TODO: Update position on resize + + // Find next portal-root class along the node tree to attack + const portalRoot = findParentWithClass(node, rootClass); + + let targetElement: HTMLElement | null; + if (portalRoot) { + targetElement = portalRoot; + } else { + targetElement = document.querySelector('main'); + } + + targetElement?.appendChild(node).focus(); + + return { + destroy() { + if (targetElement?.contains(node)) { + targetElement?.removeChild(node); + } + } + }; +}; diff --git a/src/lib/components/BasicGraph.svelte b/src/lib/components/BasicGraph.svelte index 6584aee..34f5a7a 100644 --- a/src/lib/components/BasicGraph.svelte +++ b/src/lib/components/BasicGraph.svelte @@ -18,6 +18,7 @@ import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass'; import { OutlinePass } from 'three/examples/jsm/postprocessing/OutlinePass'; import Stats from './graph/Stats.svelte'; + import Graph2D from './graph/Graph2D.svelte'; export let onHover: (position: THREE.Vector2, object?: THREE.Object3D) => void = () => {}; @@ -145,30 +146,18 @@ const animate = (time: number) => { // call all before subscribers for (const subscriber of beforeSubscribers) { - subscriber(); + subscriber(renderer, scene, camera); } + // Update tween for all animations TWEEN.update(time); + controls.update(); - - // if (mousePosition) { - // // Handle selection - // raycaster.setFromCamera(mousePosition, camera); - - // // const intersections = dataRenderer.getIntersections(raycaster); - - // // if (intersections.length === 0) { - // // outlinePass.selectedObjects = []; - // // onHover(mouseClientPosition, undefined); - // // } else { - // // outlinePass.selectedObjects = [intersections[0].object]; - // // onHover(mouseClientPosition, intersections[0].object); - // // } - // } - composer.render(); + for (const subscriber of afterSubscribers) { - subscriber(); + subscriber(renderer, scene, camera); } + requestAnimationFrame(animate); }; @@ -256,18 +245,18 @@ } -
-
- - {#if isSetupComplete} - - - {/if} +
+
+
+ + {#if isSetupComplete} + + + {/if} +
+
+ +