diff --git a/app/document/[documentId]/components/DocumentTitle/documentTitle.module.css b/app/document/[documentId]/components/DocumentTitle/documentTitle.module.css
index f0a8927..843f268 100644
--- a/app/document/[documentId]/components/DocumentTitle/documentTitle.module.css
+++ b/app/document/[documentId]/components/DocumentTitle/documentTitle.module.css
@@ -1,13 +1,13 @@
.container {
cursor: default;
box-sizing: border-box;
- height: 50px;
+ min-height: 46px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
- padding: 0 0 0 30px;
- gap: 3px;
+ padding: 0 0 0 10px;
+ gap: 10px;
}
.label {
@@ -17,7 +17,7 @@
.icon {
color: var(--background);
- width: 30px;
- font-size: 30px;
- font-variation-settings: 'FILL' 0, 'wght' 200, 'GRAD' 0, 'opsz' 24;
+ width: 24px;
+ font-size: 24px;
+ font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
}
diff --git a/app/document/[documentId]/components/DocumentTitle/index.tsx b/app/document/[documentId]/components/DocumentTitle/index.tsx
index bf418fd..fb9cb64 100644
--- a/app/document/[documentId]/components/DocumentTitle/index.tsx
+++ b/app/document/[documentId]/components/DocumentTitle/index.tsx
@@ -4,16 +4,25 @@ import 'material-symbols';
interface DocumentTitleProps {
documentName: string;
+ sourceDataType: WBSourceDataType;
}
-export default function DocumentTitle({ documentName: documentName }: DocumentTitleProps) {
+export default function DocumentTitle({ documentName, sourceDataType }: DocumentTitleProps) {
return (
-
-
문서
-
-
Chevron_Right
+
+ {typeToIcon(sourceDataType)}
+
{documentName}
);
}
+
+function typeToIcon(type: WBSourceDataType): string {
+ switch (type) {
+ case 'pdf':
+ return 'picture_as_pdf';
+ case 'audio':
+ return 'text_to_speech';
+ }
+}
diff --git a/app/document/[documentId]/components/GenerateDialogue.tsx b/app/document/[documentId]/components/GenerateDialogue.tsx
index 1d7e424..a392c8f 100644
--- a/app/document/[documentId]/components/GenerateDialogue.tsx
+++ b/app/document/[documentId]/components/GenerateDialogue.tsx
@@ -2,27 +2,43 @@
import Dialogue from '@/components/Dialogue';
import TextInput from '@/components/Dialogue/Input/TextInput';
+import MouseHandler from '@/components/WhiteBoard/MouseHandler';
+import NodeRenderer from '@/components/WhiteBoard/NodeRenderer';
import { useToast } from '@/states/toast';
import { useWhiteBoard } from '@/states/whiteboard';
import { generateGraph } from '@/utils/api';
-import { createForceBundleFromMindmap } from '@/utils/whiteboardHelper';
-import { useState } from 'react';
+import {
+ createForceBundleFromMindmap,
+ createTreeFromMindmap,
+ objNodeSorter,
+} from '@/utils/whiteboardHelper';
+import { Canvas } from '@react-three/fiber';
+import { Suspense, useEffect, useState } from 'react';
interface GenerateDialogueProps {
onCancel: () => void;
}
+type ScreenState = 'load' | 'preview' | 'input';
+type PreviewMode = 'tree' | 'force';
+
export default function GenerateDialouge({ onCancel }: GenerateDialogueProps) {
const [text, setText] = useState('');
- const [load, setLoad] = useState(false);
- const { setCurrentTool, setBundle } = useWhiteBoard((state) => ({
+ const [state, setState] = useState('input');
+ const [rawGraphData, setRawGraphData] = useState(null);
+ const [previewMode, setPreviewMode] = useState('tree');
+ const [previewBundle, setPreviewBundle] = useState(null);
+ const [previewTree, setPreviewTree] = useState(null);
+ const { setCurrentTool, setBundle, addObj, removeObj } = useWhiteBoard((state) => ({
setCurrentTool: state.setCurrentTool,
setBundle: state.setBundle,
+ addObj: state.addObj,
+ removeObj: state.removeObj,
}));
const pushToast = useToast((state) => state.pushToast);
- const onSubmit = () => {
- setLoad(true);
+ const onGenerate = () => {
+ setState('load');
// request generation
(async () => {
const res = await generateGraph({ text });
@@ -32,43 +48,155 @@ export default function GenerateDialouge({ onCancel }: GenerateDialogueProps) {
duraton: 3000,
msg: '작업을 실패했습니다.',
});
- return setLoad(false);
+ return setState('input');
}
- // generate bundle
- const bundle = createForceBundleFromMindmap(res);
+ setRawGraphData(res);
+ setState('preview');
+ })();
+ };
- setBundle(bundle);
- setCurrentTool('BUNDLE');
+ useEffect(() => {
+ // generate bundle
+ if (rawGraphData === null) return;
+ setPreviewBundle(() => {
+ switch (previewMode) {
+ case 'tree':
+ return createTreeFromMindmap(rawGraphData);
+ case 'force':
+ return createForceBundleFromMindmap(rawGraphData);
+ }
+ });
+ }, [previewMode, rawGraphData]);
+
+ useEffect(() => {
+ if (previewBundle === null) return;
+ // prepare preview
+ const children: ObjNode[] = [];
+ for (const obj of previewBundle.objs) {
+ addObj(obj, false);
+ children.push({
+ objId: obj.objId,
+ childNodes: [],
+ depth: obj.depth,
+ });
+ }
+ setPreviewTree({ objId: 'ROOT', depth: 0, childNodes: children.sort(objNodeSorter) });
+ return () => {
+ // cleanup
+ for (const obj of previewBundle.objs) {
+ removeObj(obj, false);
+ setPreviewTree(null);
+ }
+ };
+ }, [addObj, previewBundle, removeObj]);
+ const onSubmit = () => {
+ // set bundle and exit
+ if (previewBundle === null) return;
+ setState('load');
+ (async () => {
+ setBundle(previewBundle);
+ setCurrentTool('BUNDLE');
pushToast({
id: new Date().getTime(),
duraton: 5000,
msg: '그래프 생성이 완료되었습니다!\n클릭해서 원하는 위치에 붙여넣어 주세요',
});
+ cleanUp();
onCancel();
})();
};
+ const cleanUp = () => {
+ if (previewBundle === null) return;
+ // remove previewBundle objs from objmap
+ for (const obj of previewBundle.objs) {
+ removeObj(obj);
+ }
+ };
+
return (
-
- {load ? (
-
- ) : (
- setText(e.target.value)}
- label={'생성에 사용될 글'}
- multiline={true}
- />
- )}
-
+ {(() => {
+ switch (state) {
+ case 'load':
+ return (
+
+
+
+ );
+ case 'preview':
+ if (previewTree === null) return null;
+ return (
+
{
+ cleanUp();
+ onCancel();
+ }}
+ onSubmit={onSubmit}
+ enabled={true}
+ >
+ 렌더러
+
+
+
+
+
+ );
+ case 'input':
+ return (
+
+ setText(e.target.value)}
+ label={'생성에 사용될 글'}
+ multiline={true}
+ />
+
+ );
+ }
+ })()}
);
}
+
+function PreviewRenderer({ root }: { root: ObjNode }) {
+ return (
+
+ );
+}
diff --git a/app/document/[documentId]/page.module.css b/app/document/[documentId]/page.module.css
index 9a28b41..480349f 100644
--- a/app/document/[documentId]/page.module.css
+++ b/app/document/[documentId]/page.module.css
@@ -4,6 +4,13 @@
background-color: var(--secondary-dark);
}
+.divider {
+ background-color: var(--primary-light);
+ width: 10px;
+ cursor: col-resize;
+ user-select: none;
+}
+
.container {
animation: var(--intro-animation);
background-color: var(--secondary-dark);
@@ -18,8 +25,12 @@
.sideBar {
display: flex;
flex-direction: column;
- width: 350px;
- flex: 0 0 350px;
+}
+
+.viewerContainer {
+ background-color: var(--background);
+ flex-grow: 1;
+ overflow: auto;
}
.sideBarUp {
diff --git a/app/document/[documentId]/page.tsx b/app/document/[documentId]/page.tsx
index 66a1a4d..1a3ee8b 100644
--- a/app/document/[documentId]/page.tsx
+++ b/app/document/[documentId]/page.tsx
@@ -1,17 +1,13 @@
'use client';
import dynamic from 'next/dynamic';
-import { ReactNode, Suspense, useEffect, useState } from 'react';
+import { Suspense, useEffect, useState } from 'react';
import styles from './page.module.css';
import { useWhiteBoard } from '@/states/whiteboard';
import { getDocument } from '@/utils/api';
import DocumentTitle from './components/DocumentTitle';
-import ActionButtonGroup from './components/ActionButtonGroup';
-import Tab from './components/Tab';
-import ObjectPropertyEditor from '@/components/WhiteBoard/ObjectPropertyEditor';
-import TreeViewer from '@/components/WhiteBoard/TreeViewer';
import ToolSelector from '@/components/WhiteBoard/ToolSelector';
import LoadingScreen from '../../../components/LoadingScreen';
-import OverlayWrapper from '@/components/OverlayWrapper';
+import PdfViewer from '@/components/PdfViewer';
const WhiteBoard = dynamic(() => import('@/components/WhiteBoard'), { ssr: false });
interface DocumentPageProps {
@@ -25,30 +21,48 @@ export default function DoucumentsPage({ params }: DocumentPageProps) {
resetWhiteBoard: state.resetWhiteBoard,
}));
- const document = useDocument(parseInt(params.documentId));
+ const [sideBarWidth, setSideBarWidth] = useState(500);
+ const [dividerActive, setDividerActive] = useState(false);
- const [overlay, setOverlay] = useState(null);
+ useEffect(() => {
+ if (!dividerActive) return;
+ const onPointerUp = () => setDividerActive(false);
+ const onPointerMove = (e: MouseEvent) => {
+ setSideBarWidth(e.clientX - 5);
+ };
+ document.addEventListener('pointerup', onPointerUp);
+ document.addEventListener('pointermove', onPointerMove);
+ return () => {
+ document.removeEventListener('pointerup', onPointerUp);
+ document.removeEventListener('pointermove', onPointerMove);
+ };
+ }, [dividerActive]);
+
+ const documentData = useDocument(parseInt(params.documentId));
// reset whiteboard
useEffect(() => {
resetWhiteBoard();
}, [resetWhiteBoard]);
- if (document === null) return ;
+ if (documentData === null) return ;
return (
-
-
-
-
+
+
setDividerActive(true)} />
@@ -60,7 +74,6 @@ export default function DoucumentsPage({ params }: DocumentPageProps) {
-
{overlay}
);
}
diff --git a/app/globals.css b/app/globals.css
index f041dcb..223c3c5 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -104,3 +104,11 @@ div.loading-bar {
scale: 100%;
}
}
+
+mark {
+ text-decoration: underline;
+ text-decoration-color: red;
+ text-decoration-thickness: 2px;
+ color: transparent;
+ background: transparent;
+}
diff --git a/components/PdfViewer/BottomPanel/BottomPanel.module.css b/components/PdfViewer/BottomPanel/BottomPanel.module.css
new file mode 100644
index 0000000..f3d6f6f
--- /dev/null
+++ b/components/PdfViewer/BottomPanel/BottomPanel.module.css
@@ -0,0 +1,72 @@
+.container {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ border-radius: 10px 10px 0 0;
+ width: 100%;
+ background-color: var(--primary-dark);
+ overflow: clip;
+ user-select: none;
+}
+
+.handle {
+ cursor: row-resize;
+ height: 20px;
+ flex: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+}
+
+.utils {
+ width: 100%;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ align-items: center;
+ justify-content: space-around;
+ gap: 10px;
+ --background: var(--foreground);
+ color: var(--background);
+ text-align: center;
+}
+
+.documentControls {
+ gap: 5px;
+ height: 46px;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+}
+
+.tools {
+ gap: 10px;
+ height: 46px;
+ display: flex;
+ align-items: center;
+}
+
+.keywords {
+ display: flex;
+ justify-content: center;
+ width: 100%;
+ flex-wrap: wrap;
+ padding: 10px;
+ align-items: center;
+ overflow: auto;
+ gap: 5px;
+}
+
+.keyword {
+ padding: 2px 5px;
+ border-radius: 5px;
+ background-color: var(--secondary-light);
+ color: var(--primary-dark);
+}
+
+.icon {
+ cursor: pointer;
+ text-align: center;
+ color: var(--background);
+}
diff --git a/components/PdfViewer/BottomPanel/index.tsx b/components/PdfViewer/BottomPanel/index.tsx
new file mode 100644
index 0000000..2ad2759
--- /dev/null
+++ b/components/PdfViewer/BottomPanel/index.tsx
@@ -0,0 +1,157 @@
+import { Dispatch, SetStateAction, useEffect, useState } from 'react';
+import styles from './BottomPanel.module.css';
+import { SmallIconButton, ToolButton } from '@/components/WhiteBoard/ToolSelector';
+import 'material-symbols';
+
+const DEFAULT_HEIGHT = 66;
+const SCALE_MAX = 10;
+const SCALE_MIN = 1;
+
+interface BottomPanelProps {
+ currentTool: Tool;
+ setCurrentTool: (tool: Tool) => void;
+ keywords: string[];
+ setKeywords: Dispatch
>;
+ scale: number;
+ setScale: Dispatch>;
+ page: number;
+ setPage: Dispatch>;
+ numPages: number;
+}
+
+export default function BottomPanel({
+ currentTool,
+ setCurrentTool,
+ keywords,
+ setKeywords,
+ scale,
+ setScale,
+ page,
+ setPage,
+ numPages,
+}: BottomPanelProps) {
+ const [height, setHeight] = useState(DEFAULT_HEIGHT);
+ const [drag, setDrag] = useState(false);
+
+ useEffect(() => {
+ if (!drag) return;
+ const pointerUp = () => setDrag(false);
+ const pointerMove = (e: MouseEvent) =>
+ setHeight(Math.max(window.innerHeight - e.clientY + 10, DEFAULT_HEIGHT));
+ document.addEventListener('pointermove', pointerMove);
+ document.addEventListener('pointerup', pointerUp);
+ return () => {
+ document.removeEventListener('pointermove', pointerMove);
+ document.removeEventListener('pointerup', pointerUp);
+ };
+ }, [drag]);
+
+ return (
+
+
{
+ setDrag(true);
+ }}
+ >
+ e.stopPropagation()}
+ onClick={() => {
+ setHeight((height) => (height === DEFAULT_HEIGHT ? -1 : DEFAULT_HEIGHT));
+ }}
+ >
+ {height === DEFAULT_HEIGHT ? 'expand_less' : 'expand_more'}
+
+
+
+
+
{
+ setScale((scale) => Math.max(scale - 0.1, SCALE_MIN));
+ }}
+ />
+ {`${Math.round(scale * 100)}%`}
+ {
+ setScale((scale) => Math.min(scale + 0.1, SCALE_MAX));
+ }}
+ />
+ |
+ {
+ setPage((page) => {
+ const newPage = page - 1;
+ if (newPage < 0) return 0;
+ return newPage;
+ });
+ }}
+ />
+ {page + 1}
+ {
+ setPage((page) => {
+ const newPage = page + 1;
+ if (newPage >= numPages) return numPages - 1;
+ return newPage;
+ });
+ }}
+ />
+
+
+
+
+
+
+
+
+ {keywords.map((v) => (
+ {
+ setKeywords((keywords) => keywords.filter((k) => k !== v));
+ }}
+ />
+ ))}
+
+
+ );
+}
+
+interface KeywordProps {
+ label: string;
+ onClick?: () => void;
+}
+
+function Keyword({ label, onClick }: KeywordProps) {
+ return (
+
+ {label}
+
+ );
+}
diff --git a/components/PdfViewer/PdfViewer.module.css b/components/PdfViewer/PdfViewer.module.css
new file mode 100644
index 0000000..af7772e
--- /dev/null
+++ b/components/PdfViewer/PdfViewer.module.css
@@ -0,0 +1,20 @@
+.container {
+ display: flex;
+ height: 100%;
+ width: 100%;
+ flex: 0;
+ flex-direction: column;
+}
+
+.viewerContainer {
+ display: flex;
+ align-items: center;
+ flex-direction: column;
+ width: 100%;
+ flex: 1;
+ overflow: auto;
+}
+
+.viewer {
+ margin: 0 auto;
+}
diff --git a/components/PdfViewer/index.tsx b/components/PdfViewer/index.tsx
new file mode 100644
index 0000000..0a4646b
--- /dev/null
+++ b/components/PdfViewer/index.tsx
@@ -0,0 +1,142 @@
+'use client';
+import { Document, Page, pdfjs } from 'react-pdf';
+import styles from './PdfViewer.module.css';
+import 'react-pdf/dist/Page/TextLayer.css';
+import 'react-pdf/dist/Page/AnnotationLayer.css';
+import { useCallback, useState } from 'react';
+import BottomPanel from './BottomPanel';
+
+pdfjs.GlobalWorkerOptions.workerSrc = new URL(
+ 'pdfjs-dist/build/pdf.worker.min.js',
+ import.meta.url,
+).toString();
+
+interface PdfViewerProps {
+ url: string;
+}
+
+export default function PdfViewer({ url }: PdfViewerProps) {
+ const [keywords, setKeywords] = useState([]);
+ const [tool, setTool] = useState('SELECT');
+ const [scale, setScale] = useState(1);
+ const [page, setPage] = useState(0);
+ const [numPages, setNumPages] = useState(0);
+
+ const onPointerUp = () => {
+ if (tool !== 'HIGHLIGHT') return;
+ // add selection to keywords
+ const word = window.getSelection()?.toString() ?? '';
+ if (word.length === 0) return;
+ setKeywords((keywords) => [...keywords, word]);
+ };
+
+ const textRenderer = useCallback(
+ (textItem: any) => {
+ // highlights keywords
+ const pos: Pos[] = [];
+ for (const s of keywords) {
+ // find all occurences
+ const matches = (textItem.str as string).matchAll(new RegExp(s, 'gi'));
+ for (const m of matches) {
+ if (m.index === undefined) continue;
+ pos.push({ start: m.index, end: m.index + s.length });
+ }
+ }
+ // add marks
+ const str = mergeAndApplyMarks(textItem.str as string, pos);
+ return str;
+ },
+ [keywords],
+ );
+
+ return (
+
+
+
+
{
+ setNumPages(d.numPages);
+ }}
+ >
+
+
+
+
+
+
+ );
+}
+
+interface Pos {
+ start: number;
+ end: number;
+}
+
+function posSorter(a: Pos, b: Pos) {
+ // latter item comes first
+ if (a.end > b.end) {
+ return -1;
+ } else if (a.end < b.end) {
+ return 1;
+ } else {
+ return a.start > b.start ? -1 : 1;
+ }
+}
+
+export function mergeAndApplyMarks(sourceStr: string, pos: Pos[]): string {
+ let str = sourceStr;
+ // sort occurences
+ pos.sort(posSorter);
+
+ // apply occurences
+ const bounds: Pos = { start: -1, end: -1 };
+ for (const p of pos) {
+ // first
+ if (bounds.start === -1 || bounds.end === -1) {
+ // update bounds
+ bounds.end = p.end;
+ bounds.start = p.start;
+ } else if (p.end < bounds.start) {
+ // mark
+ str =
+ str.slice(0, bounds.start) +
+ '' +
+ str.slice(bounds.start, bounds.end) +
+ '' +
+ str.slice(bounds.end);
+ // update bounds
+ bounds.end = p.end;
+ bounds.start = p.start;
+ } else {
+ bounds.end = Math.max(bounds.end, p.end);
+ bounds.start = Math.min(bounds.start, p.start);
+ }
+ }
+ // apply last mark
+ if (bounds.start !== -1 || bounds.end !== -1) {
+ str =
+ str.slice(0, bounds.start) +
+ '' +
+ str.slice(bounds.start, bounds.end) +
+ '' +
+ str.slice(bounds.end);
+ }
+
+ return str;
+}
diff --git a/components/WhiteBoard/CircleObjRenderer.tsx b/components/WhiteBoard/CircleObjRenderer.tsx
new file mode 100644
index 0000000..f490a1d
--- /dev/null
+++ b/components/WhiteBoard/CircleObjRenderer.tsx
@@ -0,0 +1,34 @@
+'use client';
+import { Circle } from '@react-three/drei';
+import { ObjRendererProps, RendererProps } from './NodeRenderer';
+import { useWhiteBoard } from '@/states/whiteboard';
+import { useFrame } from '@react-three/fiber';
+
+export function CircleRenderer({ objId, dimensionsRef, groupRef }: RendererProps) {
+ const obj = useWhiteBoard((state) => state.objMap.get(objId) as CircleObj);
+ useFrame(() => {
+ if (groupRef === undefined || groupRef.current === null || obj === undefined) return;
+ groupRef.current.position.setX(obj.x + obj.r);
+ groupRef.current.position.setY(obj.y + obj.r);
+ groupRef.current.position.setZ(obj.depth);
+ });
+ if (obj === undefined) return <>>;
+ return ;
+}
+
+export default function CircleObjRenderer({ rawObj, dimensionsRef }: ObjRendererProps) {
+ const obj = rawObj as CircleObj;
+
+ if (dimensionsRef !== undefined) {
+ dimensionsRef.current.x = -obj.r;
+ dimensionsRef.current.y = -obj.r;
+ dimensionsRef.current.w = obj.r * 2;
+ dimensionsRef.current.h = obj.r * 2;
+ }
+
+ return (
+
+
+
+ );
+}
diff --git a/components/WhiteBoard/GraphRenderer.tsx b/components/WhiteBoard/GraphRenderer.tsx
new file mode 100644
index 0000000..f71beb5
--- /dev/null
+++ b/components/WhiteBoard/GraphRenderer.tsx
@@ -0,0 +1,272 @@
+'use client';
+import * as d3 from 'd3';
+import { RendererProps } from './NodeRenderer';
+import { useEffect, useMemo, useRef, useState } from 'react';
+import { invalidate, useFrame } from '@react-three/fiber';
+import * as THREE from 'three';
+import { Group } from 'three';
+import { useWhiteBoard } from '@/states/whiteboard';
+import { DEFAULT_FONT, calculateLineGeometry, genId } from '@/utils/whiteboardHelper';
+// @ts-ignore
+import { Text, preloadFont } from 'troika-three-text';
+import { Text as DreiText } from '@react-three/drei';
+import { FlatLine, FlatLineRef } from './LineObjRenderer';
+
+// Live graph : graph constantly updated by text2graph model, user cannot modify
+export function LiveGraphRenderer({ objId, dimensionsRef }: RendererProps) {
+ const planeMaterial = useMemo(() => {
+ const material = new THREE.MeshBasicMaterial({ color: 'grey', transparent: false });
+ material.depthTest = true;
+ material.depthWrite = true;
+ return material;
+ }, []);
+ const planeGeometry = useMemo(() => new THREE.PlaneGeometry(1, 1), []);
+
+ const obj = useWhiteBoard((state) => state.objMap.get(objId) as LiveGraphObj);
+
+ const graphRef = useRef>();
+ const dataRef = useRef>();
+ const groupRef = useRef(null);
+ const [fontLoaded, setFontLoaded] = useState(false);
+
+ // render after font preload
+ preloadFont({ font: DEFAULT_FONT }, () => {
+ setFontLoaded(true);
+ invalidate();
+ });
+
+ useFrame(() => {
+ if (
+ dataRef.current === undefined ||
+ graphRef.current === undefined ||
+ dimensionsRef === undefined ||
+ groupRef.current === null
+ )
+ return;
+ dimensionsRef.current.x = obj.x;
+ dimensionsRef.current.y = obj.y;
+ groupRef.current.position.set(obj.x, obj.y, obj.depth);
+ });
+
+ // update tree layout
+ useEffect(() => {
+ if (groupRef.current === null) return;
+ // remove items from mesh group
+ for (const child of groupRef.current.children) {
+ child.removeFromParent();
+ if (child.hasOwnProperty('dispose')) (child as any).dispose(); // prevent memory leak
+ }
+ groupRef.current.clear();
+
+ if (!fontLoaded) return;
+
+ const children = new Map(Object.entries(obj.data.graph));
+ const root = d3.hierarchy(obj.data.root, (d) => {
+ return children.get(d.toString());
+ });
+
+ graphRef.current = d3.tree().nodeSize([30, 300]);
+ dataRef.current = graphRef.current(root);
+
+ // link meshes
+ for (const v of dataRef.current.links()) {
+ const link = new THREE.Mesh(planeGeometry, planeMaterial);
+ const { w, d } = calculateLineGeometry(v.source.y, v.source.x, v.target.y, v.target.x);
+ link.scale.setX(w);
+ link.rotation.set(0, 0, d);
+ link.position.set((v.source.y + v.target.y) / 2, (v.source.x + v.target.x) / 2, obj.depth);
+ groupRef.current.add(link);
+ }
+
+ // node meshes
+ for (const v of dataRef.current.descendants()) {
+ const text = new Text();
+ text.name = 'label';
+ text.font = DEFAULT_FONT;
+ text.fontSize = 15;
+ text.text = obj.data.keywords[v.data];
+ text.color = 'black';
+ text.position.setX(v.y);
+ text.position.setY(v.x);
+ text.position.setZ(obj.depth);
+ text.anchorX = 'center';
+ text.anchorY = 'middle';
+ text.transparent = false;
+ text.outlineWidth = 5;
+ text.outlineColor = 'white';
+ groupRef.current.add(text);
+ }
+ }, [
+ fontLoaded,
+ obj.data.graph,
+ obj.data.keywords,
+ obj.data.root,
+ obj.depth,
+ planeGeometry,
+ planeMaterial,
+ ]);
+
+ return (
+ {
+ // TODO: create a proper ui for this function
+ // fixes and objectify current LiveGraph
+ objectifyGraph(objId);
+ }}
+ ref={groupRef}
+ >
+ );
+}
+
+export function GraphRootRenderer({ objId, dimensionsRef, groupRef }: RendererProps) {
+ const obj = useWhiteBoard((state) => state.objMap.get(objId) as GraphRootObj);
+
+ useFrame(() => {
+ if (groupRef === undefined || groupRef.current === null || obj === undefined) return;
+ groupRef.current.position.setX(obj.x);
+ groupRef.current.position.setY(obj.y);
+ groupRef.current.position.setZ(obj.depth);
+ });
+
+ return (
+ {
+ if (geometry.boundingBox === null || dimensionsRef === undefined) return;
+ dimensionsRef.current.h = 10 + geometry.boundingBox.max.y - geometry.boundingBox.min.y;
+ dimensionsRef.current.w = 10 + geometry.boundingBox.max.x - geometry.boundingBox.min.x;
+ dimensionsRef.current.x = geometry.boundingBox.min.x - 5;
+ dimensionsRef.current.y = geometry.boundingBox.min.y - 5;
+ }}
+ >
+ {obj.label}
+
+ );
+}
+
+export function GraphNodeRenderer({ objId, dimensionsRef, groupRef }: RendererProps) {
+ const obj = useWhiteBoard((state) => state.objMap.get(objId) as GraphNodeObj);
+ const lineRef = useRef(null);
+
+ useFrame(() => {
+ if (
+ groupRef === undefined ||
+ groupRef.current === null ||
+ obj === undefined ||
+ lineRef.current === null
+ )
+ return;
+ groupRef.current.position.setX(obj.x);
+ groupRef.current.position.setY(obj.y);
+ groupRef.current.position.setZ(-0.00000000001); // gap between nodes
+ lineRef.current.setPoints(0, 0, -obj.x, -obj.y, 1);
+ });
+
+ return (
+ <>
+ {
+ if (geometry.boundingBox === null || dimensionsRef === undefined) return;
+ dimensionsRef.current.h = 10 + geometry.boundingBox.max.y - geometry.boundingBox.min.y;
+ dimensionsRef.current.w = 10 + geometry.boundingBox.max.x - geometry.boundingBox.min.x;
+ dimensionsRef.current.x = geometry.boundingBox.min.x - 5;
+ dimensionsRef.current.y = geometry.boundingBox.min.y - 5;
+ }}
+ >
+ {obj.label}
+
+
+ >
+ );
+}
+
+// Live graph -> graph: convert every node to objs
+function objectifyGraph(objId: string) {
+ const obj = useWhiteBoard.getState().objMap.get(objId) as LiveGraphObj;
+ const objs: Obj[] = [];
+
+ // create graph data
+ const children = new Map(Object.entries(obj.data.graph));
+ const root = d3.hierarchy(obj.data.root, (d) => {
+ return children.get((d as number).toString());
+ });
+
+ // create tree layout
+ const tree = d3.tree().nodeSize([30, 300])(root);
+
+ // nodes
+ const nodes = new Map();
+ for (const v of tree.descendants()) {
+ const node: GraphNodeObj | GraphRootObj =
+ v.parent === null
+ ? {
+ type: 'GRAPHROOT',
+ label: obj.data.keywords[v.data],
+ objId: obj.objId,
+ x: v.y,
+ y: v.x,
+ depth: obj.depth,
+ parentId: obj.parentId,
+ }
+ : {
+ type: 'GRAPHNODE',
+ label: obj.data.keywords[v.data],
+ objId: obj.data.keywords[v.data] + genId(),
+ x: v.y - (v.parent?.y ?? 0),
+ y: v.x - (v.parent?.x ?? 0),
+ depth: obj.depth,
+ parentId: obj.objId,
+ };
+ nodes.set(v.data, node);
+ }
+
+ // edges
+ for (const v of tree.links()) {
+ const parent = nodes.get(v.source.data);
+ const child = nodes.get(v.target.data);
+ if (parent === undefined || child === undefined) continue;
+ child.parentId = parent.objId;
+ child.x;
+ child.y;
+ }
+
+ for (const [_i, node] of nodes) {
+ objs.push(node);
+ }
+
+ for (const newObj of objs) {
+ // change current Obj (liveGraph -> graph)
+ if (newObj.objId === obj.objId) useWhiteBoard.getState().updateObj(newObj);
+ // add new objs (nodes, edges)
+ else useWhiteBoard.getState().addObj(newObj, false);
+ }
+
+ // update render tree
+ useWhiteBoard.getState().syncObjTree();
+}
diff --git a/components/WhiteBoard/LineObjRenderer.tsx b/components/WhiteBoard/LineObjRenderer.tsx
new file mode 100644
index 0000000..7936c6c
--- /dev/null
+++ b/components/WhiteBoard/LineObjRenderer.tsx
@@ -0,0 +1,88 @@
+'use client';
+import { ThreeEvent, useFrame } from '@react-three/fiber';
+import { forwardRef, useImperativeHandle, useMemo, useRef } from 'react';
+import { Euler, Mesh } from 'three';
+import { ObjRendererProps, RendererProps } from './NodeRenderer';
+import { useWhiteBoard } from '@/states/whiteboard';
+import { calculateLineGeometry } from '@/utils/whiteboardHelper';
+
+export function LineRenderer({ objId, dimensionsRef, groupRef }: RendererProps) {
+ const obj = useWhiteBoard((state) => state.objMap.get(objId) as LineObj);
+ useFrame(() => {
+ if (groupRef === undefined || groupRef.current === null || obj === undefined) return;
+ groupRef.current.position.setX(Math.min(obj.x, obj.x2));
+ groupRef.current.position.setY(Math.min(obj.y, obj.y2));
+ groupRef.current.position.setZ(obj.depth);
+ });
+
+ if (obj === undefined) return <>>;
+ return ;
+}
+
+export default function LineObjRenderer({ rawObj, dimensionsRef }: ObjRendererProps) {
+ const obj = rawObj as LineObj;
+ const baseX = Math.min(obj.x, obj.x2);
+ const baseY = Math.min(obj.y, obj.y2);
+
+ if (dimensionsRef !== undefined) {
+ dimensionsRef.current.x = 0;
+ dimensionsRef.current.y = 0;
+ dimensionsRef.current.w = Math.abs(obj.x - obj.x2);
+ dimensionsRef.current.h = Math.abs(obj.y - obj.y2);
+ }
+
+ return (
+
+ );
+}
+
+interface FlatLineProps {
+ x: number;
+ y: number;
+ x2: number;
+ y2: number;
+ strokeWidth: number;
+ color: string;
+ depth: number;
+ onPointerDown?: (event: ThreeEvent) => void;
+}
+
+export interface FlatLineRef {
+ setPoints: (x: number, y: number, x2: number, y2: number, strokeWidth: number) => void;
+}
+
+export const FlatLine = forwardRef((props, ref) => {
+ const { x, y, x2, y2, strokeWidth, color, depth, onPointerDown } = props;
+ const { w, d } = useMemo(() => calculateLineGeometry(x, y, x2, y2), [x, x2, y, y2]);
+ const meshRef = useRef(null!);
+ useImperativeHandle(ref, () => ({
+ setPoints: (x: number, y: number, x2: number, y2: number, strokeWidth: number) => {
+ const { w, d } = calculateLineGeometry(x, y, x2, y2);
+ meshRef.current.position.set((x + x2) / 2, (y + y2) / 2, depth);
+ meshRef.current.setRotationFromEuler(new Euler(0, 0, d));
+ meshRef.current.scale.set(w, strokeWidth, 1);
+ },
+ }));
+
+ return (
+
+
+
+
+ );
+});
+FlatLine.displayName = 'FlatLine';
diff --git a/components/WhiteBoard/LineRenderer.tsx b/components/WhiteBoard/LineRenderer.tsx
deleted file mode 100644
index 7adb192..0000000
--- a/components/WhiteBoard/LineRenderer.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-'use client';
-import { ThreeEvent } from '@react-three/fiber';
-import { MutableRefObject, forwardRef, useImperativeHandle, useMemo, useRef } from 'react';
-import { useWhiteBoard } from '../../states/whiteboard';
-import { Euler, Mesh } from 'three';
-
-interface LineRendererProps {
- objId: string;
- dimensionsRef: MutableRefObject;
-}
-export default function LineRenderer({ objId, dimensionsRef }: LineRendererProps) {
- const obj = useWhiteBoard((state) => state.objMap.get(objId))! as LineObj;
-
- dimensionsRef.current.x = Math.min(obj.x, obj.x2);
- dimensionsRef.current.y = Math.min(obj.y, obj.y2);
- dimensionsRef.current.w = Math.abs(obj.x - obj.x2);
- dimensionsRef.current.h = Math.abs(obj.y - obj.y2);
-
- return (
-
- );
-}
-
-interface FlatLineProps {
- x: number;
- y: number;
- x2: number;
- y2: number;
- strokeWidth: number;
- color: string;
- depth: number;
- onPointerDown?: (event: ThreeEvent) => void;
-}
-
-export interface FlatLineRef {
- setPoints: (x: number, y: number, x2: number, y2: number, strokeWidth: number) => void;
-}
-
-export const FlatLine = forwardRef((props, ref) => {
- const { x, y, x2, y2, strokeWidth, color, depth, onPointerDown } = props;
- const { w, d } = useMemo(() => calculate(x, y, x2, y2), [x, x2, y, y2]);
- const meshRef = useRef(null!);
- useImperativeHandle(ref, () => ({
- setPoints: (x: number, y: number, x2: number, y2: number, strokeWidth: number) => {
- const { w, d } = calculate(x, y, x2, y2);
- meshRef.current.position.set((x + x2) / 2, (y + y2) / 2, depth);
- meshRef.current.setRotationFromEuler(new Euler(0, 0, d));
- meshRef.current.scale.set(w, strokeWidth, 1);
- },
- }));
-
- return (
-
-
-
-
- );
-});
-FlatLine.displayName = 'FlatLine';
-
-function calculate(x: number, y: number, x2: number, y2: number) {
- const w = Math.sqrt(Math.pow(x - x2, 2) + Math.pow(y - y2, 2));
- const d = Math.atan2(y2 - y, x2 - x);
- return { w, d };
-}
diff --git a/components/WhiteBoard/MouseHandler.tsx b/components/WhiteBoard/MouseHandler.tsx
index 378ebc1..827ddeb 100644
--- a/components/WhiteBoard/MouseHandler.tsx
+++ b/components/WhiteBoard/MouseHandler.tsx
@@ -5,6 +5,7 @@ import {
SELECT_DEPTH,
SELECT_HIGHLIGHT,
boundNumber,
+ createCircle,
createLine,
createRect,
createText,
@@ -13,7 +14,7 @@ import {
} from '@/utils/whiteboardHelper';
import { Clock, Vector2 } from 'three';
import { useWhiteBoard } from '@/states/whiteboard';
-import { FlatLine } from './LineRenderer';
+import { FlatLine } from './LineObjRenderer';
const MAX_OPACITY = 0.5;
const WHEEL_DELTA_FACTOR = 100;
@@ -22,7 +23,11 @@ const PAN_MAX_DELTA = 100;
const MAX_ZOOM = 10000;
const MIN_ZOOM = 0.1;
-export default function MouseHandler() {
+interface MouseHandlerProps {
+ forceTool?: Tool;
+}
+
+export default function MouseHandler({ forceTool }: MouseHandlerProps) {
const {
invalidate,
mouse,
@@ -44,7 +49,7 @@ export default function MouseHandler() {
setDrag,
} = useWhiteBoard((state) => ({
bundle: state.bundle,
- currentTool: state.currentTool,
+ currentTool: forceTool ?? state.currentTool,
setCurrentTool: state.setCurrentTool,
objMap: state.objMap,
addObj: state.addObj,
@@ -61,7 +66,7 @@ export default function MouseHandler() {
const [bundlePos, setBundlePos] = useState({ x: 0, y: 0 });
- const { upPos, setUpPos, upTime, setUpTime } = usePointerUp(
+ const { upPos, setUpPos } = usePointerUp(
mouse,
camera,
currentTool,
@@ -84,7 +89,6 @@ export default function MouseHandler() {
setDraw,
setOpacity,
setUpPos,
- setUpTime,
setCurrentObj,
);
@@ -106,15 +110,6 @@ export default function MouseHandler() {
useDraw(currentTool, upPos, downPos, draw, setDraw, addObj);
useFrame((s) => {
- // update opacity (if selection is active)
- if (drag !== null) {
- setSelection(false);
- } else if (upTime > 0 && selection) {
- const newO = MAX_OPACITY - (s.clock.elapsedTime - upTime);
- if (newO < 0) setSelection(false);
- else setOpacity(newO);
- }
-
// update camera position (if pan is active)
if (cameraPan) {
const newPos = getPos(s.mouse, s.camera);
@@ -153,6 +148,7 @@ export default function MouseHandler() {
switch (currentTool) {
case 'SELECT':
case 'RECT':
+ case 'CIRCLE':
case 'TEXT':
if (drag || !selection) return null;
return (
@@ -225,7 +221,6 @@ const usePointerUp = (
setDrag: (drag: DragData | null) => void,
) => {
const [upPos, setUpPos] = useState({ x: 0, y: 0 }); // mouse down position
- const [upTime, setUpTime] = useState(0);
// pointer up
useEffect(() => {
@@ -248,10 +243,10 @@ const usePointerUp = (
break;
case 'RECT':
case 'LINE':
+ case 'CIRCLE':
case 'TEXT':
if (e.button == 0) {
setUpPos(newPos);
- setUpTime(0);
setSelection(false);
setDraw(true);
}
@@ -259,8 +254,8 @@ const usePointerUp = (
case 'SELECT':
if (e.button == 0) {
setUpPos(newPos);
- setUpTime(clock.elapsedTime);
}
+ setSelection(false);
break;
case 'BUNDLE':
if (e.button == 0) {
@@ -286,7 +281,7 @@ const usePointerUp = (
tool,
]);
- return { upPos, setUpPos, upTime, setUpTime };
+ return { upPos, setUpPos };
};
const usePointerDown = (
@@ -299,7 +294,6 @@ const usePointerDown = (
setDraw: Dispatch>,
setOpacity: Dispatch>,
setUpPos: Dispatch>,
- setUpTime: Dispatch>,
setCurrentObj: (obj: string | null) => void,
) => {
const [downPos, setDownPos] = useState({ x: 0, y: 0 }); // mouse down position
@@ -328,6 +322,7 @@ const usePointerDown = (
case 'RECT':
case 'LINE':
case 'TEXT':
+ case 'CIRCLE':
setDraw(false);
e.stopPropagation(); // fall through
case 'SELECT': // selection box on left click
@@ -336,7 +331,6 @@ const usePointerDown = (
setOpacity(MAX_OPACITY);
setUpPos(newPos);
setDownPos(newPos);
- setUpTime(0);
setCurrentObj(null);
}
break;
@@ -357,7 +351,6 @@ const usePointerDown = (
setOpacity,
setSelection,
setUpPos,
- setUpTime,
tool,
]);
@@ -460,6 +453,8 @@ const useDraw = (
return createLine(downPos.x, downPos.y, upPos.x, upPos.y);
case 'TEXT':
return createText(newObjPos.x, newObjPos.y, newObjSize.x);
+ case 'CIRCLE':
+ return createCircle(newObjPos.x, newObjPos.y, Math.min(newObjSize.x, newObjSize.y) / 2);
}
return null;
})();
@@ -504,6 +499,27 @@ function handleDrag(obj: Obj, newPos: Coord, drag: DragData, updateObj: (obj: Ob
break;
case 'LINE':
return handleLineDrag(obj as LineObj, newPos, drag, updateObj);
+ case 'CIRCLE':
+ return handleCircleDrag(obj as CircleObj, newPos, drag, updateObj);
+ case 'GRAPHNODE':
+ case 'GRAPHROOT':
+ return handleGraphNodeDrag(obj as GraphNodeObj, newPos, drag, updateObj);
+ }
+}
+
+function handleGraphNodeDrag(
+ obj: GraphNodeObj,
+ newPos: Coord,
+ drag: DragData,
+ updateObj: (obj: Obj) => void,
+) {
+ switch (drag.mode) {
+ case 'move':
+ return updateObj({
+ ...obj,
+ x: validateValue(newPos.x + drag.prevObj.x - drag.mousePos.x),
+ y: validateValue(newPos.y + drag.prevObj.y - drag.mousePos.y),
+ });
}
}
@@ -545,6 +561,44 @@ function handleRectDrag(
}
}
+function handleCircleDrag(
+ obj: CircleObj,
+ newPos: Coord,
+ drag: DragData,
+ updateObj: (obj: Obj) => void,
+) {
+ switch (drag.mode) {
+ case 'move':
+ return updateObj({
+ ...obj,
+ x: validateValue(newPos.x + drag.prevObj.x - drag.mousePos.x),
+ y: validateValue(newPos.y + drag.prevObj.y - drag.mousePos.y),
+ } as Obj);
+ case 'n':
+ return updateObj({
+ ...obj,
+ r: validateValue((newPos.y - drag.prevObj.y) / 2, true),
+ } as Obj);
+ case 'e':
+ return updateObj({
+ ...obj,
+ r: validateValue((newPos.x - drag.prevObj.x) / 2, true),
+ } as Obj);
+ case 'w':
+ return updateObj({
+ ...obj,
+ r: validateValue(drag.prevObj.x + (drag.prevObj as CircleObj).r * 2 - newPos.x, true) / 2,
+ x: validateValue(newPos.x),
+ } as Obj);
+ case 's':
+ return updateObj({
+ ...obj,
+ r: validateValue(drag.prevObj.y + (drag.prevObj as CircleObj).r * 2 - newPos.y, true) / 2,
+ y: validateValue(newPos.y),
+ } as Obj);
+ }
+}
+
function handleTextDrag(
obj: TextObj,
newPos: Coord,
diff --git a/components/WhiteBoard/NodeRenderer.tsx b/components/WhiteBoard/NodeRenderer.tsx
index 9d31f01..db48fb3 100644
--- a/components/WhiteBoard/NodeRenderer.tsx
+++ b/components/WhiteBoard/NodeRenderer.tsx
@@ -1,57 +1,135 @@
'use client';
import { useWhiteBoard } from '@/states/whiteboard';
-import RectangleRenderer from './RectangleRenderer';
-import TextRenderer from './TextRenderer';
import { useThree } from '@react-three/fiber';
import { getPos } from '@/utils/whiteboardHelper';
import SelectionRenderer from './SelectionRenderer';
-import { MutableRefObject, memo, useRef } from 'react';
-import LineRenderer from './LineRenderer';
+import { MutableRefObject, RefObject, memo, useRef } from 'react';
+import { RectangleRenderer } from './RectangleObjRenderer';
+import { TextRenderer } from './TextObjRenderer';
+import { LineRenderer } from './LineObjRenderer';
+import { CircleRenderer } from './CircleObjRenderer';
+import { GraphNodeRenderer, GraphRootRenderer, LiveGraphRenderer } from './GraphRenderer';
+import { Group } from 'three';
+
+export interface ObjRendererProps {
+ rawObj: Obj;
+ dimensionsRef?: MutableRefObject;
+ dimensions?: ObjDimensions;
+}
+
+export interface RendererProps {
+ objId: string;
+ dimensionsRef?: MutableRefObject;
+ groupRef?: RefObject;
+}
interface NodeRendererProps {
node: ObjNode;
}
export default function NodeRenderer({ node }: NodeRendererProps) {
- const obj = useWhiteBoard((state) => state.objMap.get(node.objId));
+ const objExists = useWhiteBoard((state) => state.objMap.get(node.objId) !== undefined);
+ const groupRef = useRef(null);
return (
- <>
- {obj === undefined ? <>> : }
+
+ {objExists ? : <>>}
{node.childNodes.map((n) => {
return ;
})}
- >
+
);
}
interface RenderWrapperProps {
- objId: string;
- type: ObjType;
+ obj: Obj;
dimensionsRef: MutableRefObject;
+ groupRef?: RefObject;
}
-function RenderWrapper({ objId, type, dimensionsRef }: RenderWrapperProps) {
- switch (type) {
+function RenderWrapper({ obj, dimensionsRef, groupRef }: RenderWrapperProps) {
+ switch (obj.type) {
case 'RECT':
- return ;
+ return (
+
+ );
case 'TEXT':
- return ;
+ return (
+
+ );
case 'LINE':
- return ;
+ return (
+
+ );
+ case 'CIRCLE':
+ return (
+
+ );
+ case 'LIVEGRAPH':
+ return (
+
+ );
+ case 'GRAPHNODE':
+ return (
+
+ );
+ case 'GRAPHROOT':
+ return (
+
+ );
}
}
const MemoizedRenderWrapper = memo(
RenderWrapper,
- (prev, next) => prev.objId === next.objId && prev.dimensionsRef === next.dimensionsRef,
+ (prev, next) =>
+ prev.obj.objId === next.obj.objId &&
+ prev.dimensionsRef === next.dimensionsRef &&
+ prev.obj.type === next.obj.type &&
+ prev.groupRef === next.groupRef,
);
interface ObjectWrapperProps {
+ groupRef?: RefObject;
objId: string;
}
-function ObjectWrapper({ objId }: ObjectWrapperProps) {
+function ObjectWrapper({ objId, groupRef }: ObjectWrapperProps) {
const obj = useWhiteBoard((state) => state.objMap.get(objId))!;
const dimensionsRef = useRef({ x: 0, y: 0, w: 0, h: 0 });
const { currentObj, setCurrentObj, setDrag, currentTool } = useWhiteBoard((state) => ({
@@ -61,14 +139,15 @@ function ObjectWrapper({ objId }: ObjectWrapperProps) {
currentTool: state.currentTool,
}));
const { mouse, camera } = useThree();
- const selection = currentObj === obj.objId;
+ const selection = currentObj === objId;
+
return (
{
// 첫번째 클릭만 여기서 처리, selection 이후는 selectionRenderer에서 처리
e.stopPropagation();
if (e.button === 0) {
- setCurrentObj(obj.objId);
+ setCurrentObj(objId);
if (selection) return;
if (currentTool === 'SELECT') {
const mousePos = getPos(mouse, camera);
@@ -81,7 +160,7 @@ function ObjectWrapper({ objId }: ObjectWrapperProps) {
}
}}
>
-
+
{selection ? : <>>}
);
diff --git a/components/WhiteBoard/ObjectPropertyEditor/index.tsx b/components/WhiteBoard/ObjectPropertyEditor/index.tsx
index 41d7f8e..5e25010 100644
--- a/components/WhiteBoard/ObjectPropertyEditor/index.tsx
+++ b/components/WhiteBoard/ObjectPropertyEditor/index.tsx
@@ -45,6 +45,12 @@ export default function ObjectPropertyEditor({ targetObjId }: ObjectPropertyEdit
panels.push(
,
);
+ break;
+ case 'CIRCLE':
+ panels.push(
+ ,
+ );
+ break;
case 'ROOT':
}
@@ -212,6 +218,27 @@ function LinePanel({ obj, onChange }: LinePanelProps) {
);
}
+interface CirclePanelProps {
+ obj: CircleObj;
+ onChange: (key: string, val: any) => void;
+}
+
+function CirclePanel({ obj, onChange }: CirclePanelProps) {
+ return (
+
+ );
+}
+
interface PropertyProps {
propKey: string;
label?: string;
diff --git a/components/WhiteBoard/RectangleObjRenderer.tsx b/components/WhiteBoard/RectangleObjRenderer.tsx
new file mode 100644
index 0000000..089d1f0
--- /dev/null
+++ b/components/WhiteBoard/RectangleObjRenderer.tsx
@@ -0,0 +1,40 @@
+'use client';
+import { useWhiteBoard } from '@/states/whiteboard';
+import { ObjRendererProps, RendererProps } from './NodeRenderer';
+import { useFrame } from '@react-three/fiber';
+
+export function RectangleRenderer({ objId, dimensionsRef, groupRef }: RendererProps) {
+ const obj = useWhiteBoard((state) => state.objMap.get(objId));
+ useFrame(() => {
+ if (groupRef === undefined || groupRef.current === null || obj === undefined) return;
+ groupRef.current.position.setX(obj.x);
+ groupRef.current.position.setY(obj.y);
+ groupRef.current.position.setZ(obj.depth); // gap between nodes
+ });
+ if (obj === undefined) return <>>;
+ return ;
+}
+
+// renders given rectangle object, sets selection onClick
+export default function RectangleObjRenderer({ rawObj, dimensionsRef }: ObjRendererProps) {
+ const obj = rawObj as RectObj;
+
+ if (dimensionsRef !== undefined) {
+ dimensionsRef.current.x = 0;
+ dimensionsRef.current.y = 0;
+ dimensionsRef.current.w = obj.w;
+ dimensionsRef.current.h = obj.h;
+ }
+
+ return (
+
+
+
+
+ );
+}
diff --git a/components/WhiteBoard/RectangleRenderer.tsx b/components/WhiteBoard/RectangleRenderer.tsx
deleted file mode 100644
index 957b214..0000000
--- a/components/WhiteBoard/RectangleRenderer.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-'use client';
-
-import { MutableRefObject } from 'react';
-import { useWhiteBoard } from '../../states/whiteboard';
-
-interface Props {
- objId: string;
- dimensionsRef: MutableRefObject;
-}
-
-// renders given rectangle object, sets selection onClick
-export default function RectangleRenderer({ objId, dimensionsRef }: Props) {
- const obj = useWhiteBoard((state) => state.objMap.get(objId))! as RectObj;
- dimensionsRef.current.x = obj.x;
- dimensionsRef.current.y = obj.y;
- dimensionsRef.current.w = obj.w;
- dimensionsRef.current.h = obj.h;
- return (
-
-
-
-
- );
-}
diff --git a/components/WhiteBoard/SelectionRenderer.tsx b/components/WhiteBoard/SelectionRenderer.tsx
index d27b26a..45f91e3 100644
--- a/components/WhiteBoard/SelectionRenderer.tsx
+++ b/components/WhiteBoard/SelectionRenderer.tsx
@@ -11,7 +11,7 @@ import {
import { Circle } from '@react-three/drei';
import { ThreeEvent, useFrame, useThree } from '@react-three/fiber';
import { MutableRefObject, forwardRef, useImperativeHandle, useRef } from 'react';
-import { FlatLine, FlatLineRef } from './LineRenderer';
+import { FlatLine, FlatLineRef } from './LineObjRenderer';
import { BufferGeometry, Mesh, NormalBufferAttributes } from 'three';
interface SelectionRendererProps {
@@ -55,7 +55,6 @@ export default function SelectionRenderer({ dimensionsRef, objId }: SelectionRen
if (dimensionsRef.current.h <= 0) dimensionsRef.current.h = 0;
if (dimensionsRef.current.w <= 0) dimensionsRef.current.w = 0;
- if (dimensionsRef.current.h === 0 && dimensionsRef.current.w === 0) return;
return (
<>
@@ -252,12 +251,14 @@ interface LinePointsProps {
}
function LinePoints({ obj, onPointerDown }: LinePointsProps) {
+ const baseX = Math.min(obj.x, obj.x2);
+ const baseY = Math.min(obj.y, obj.y2);
return (
<>
{/* NE */}
- onPointerDown(e, 'ne')} x={obj.x} y={obj.y} />
+ onPointerDown(e, 'ne')} x={obj.x - baseX} y={obj.y - baseY} />
{/* SW */}
- onPointerDown(e, 'sw')} x={obj.x2} y={obj.y2} />
+ onPointerDown(e, 'sw')} x={obj.x2 - baseX} y={obj.y2 - baseY} />
>
);
}
diff --git a/components/WhiteBoard/TextObjRenderer.tsx b/components/WhiteBoard/TextObjRenderer.tsx
new file mode 100644
index 0000000..6ac1d53
--- /dev/null
+++ b/components/WhiteBoard/TextObjRenderer.tsx
@@ -0,0 +1,67 @@
+'use client';
+import { Text } from '@react-three/drei';
+import { invalidate, useFrame } from '@react-three/fiber';
+import { ObjRendererProps, RendererProps } from './NodeRenderer';
+import { useWhiteBoard } from '@/states/whiteboard';
+import { DEFAULT_FONT } from '@/utils/whiteboardHelper';
+
+export function TextRenderer({ objId, dimensionsRef, groupRef }: RendererProps) {
+ const obj = useWhiteBoard((state) => state.objMap.get(objId) as TextObj);
+ useFrame(() => {
+ const position = calculatePosition(obj);
+ if (groupRef !== undefined && groupRef.current !== null) {
+ groupRef.current.position.setX(position.x);
+ groupRef.current.position.setY(position.y);
+ groupRef.current.position.setZ(obj.depth);
+ }
+ if (dimensionsRef !== undefined) {
+ dimensionsRef.current.w = obj.w;
+ dimensionsRef.current.x = 0;
+ dimensionsRef.current.y = 0;
+ }
+ });
+
+ if (obj === undefined) return <>>;
+
+ return ;
+}
+
+export default function TextObjRenderer({ rawObj, dimensionsRef }: ObjRendererProps) {
+ const obj = rawObj as TextObj;
+ return (
+ {
+ if (geometry.boundingBox === null || dimensionsRef === undefined) return;
+ const newHeight = geometry.boundingBox.max.y - geometry.boundingBox.min.y;
+ if (dimensionsRef.current.h != newHeight) {
+ dimensionsRef.current.h = newHeight;
+ invalidate();
+ }
+ }}
+ >
+ {obj.text}
+
+ );
+}
+
+function calculatePosition(obj: TextObj) {
+ const position = { x: obj.x, y: obj.y };
+ switch (obj.textAlign) {
+ case 'center':
+ return { ...position, x: obj.x + obj.w / 2 };
+ case 'left':
+ return position;
+ case 'right':
+ return { ...position, x: obj.x + obj.w };
+ }
+}
diff --git a/components/WhiteBoard/TextRenderer.tsx b/components/WhiteBoard/TextRenderer.tsx
deleted file mode 100644
index e1e8140..0000000
--- a/components/WhiteBoard/TextRenderer.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-'use client';
-import { Text } from '@react-three/drei';
-import { MutableRefObject } from 'react';
-import { useWhiteBoard } from '../../states/whiteboard';
-import { useThree } from '@react-three/fiber';
-
-interface TextViewProps {
- objId: string;
- dimensionsRef: MutableRefObject;
-}
-
-export default function TextRenderer({ objId, dimensionsRef }: TextViewProps) {
- const obj = useWhiteBoard((state) => state.objMap.get(objId))! as TextObj;
- const { invalidate } = useThree();
-
- dimensionsRef.current.w = obj.w;
- dimensionsRef.current.x = obj.x;
- dimensionsRef.current.y = obj.y;
-
- const position = calculatePosition(obj);
-
- return (
- {
- if (geometry.boundingBox === null) return;
- const newHeight = geometry.boundingBox.max.y - geometry.boundingBox.min.y;
- if (dimensionsRef.current.h !== newHeight) {
- dimensionsRef.current.h = newHeight;
- invalidate();
- }
- }}
- >
- {obj.text}
-
- );
-}
-
-function calculatePosition(obj: TextObj) {
- const position = { x: obj.x, y: obj.y };
- switch (obj.textAlign) {
- case 'center':
- return { ...position, x: obj.x + obj.w / 2 };
- case 'left':
- return position;
- case 'right':
- return { ...position, x: obj.x + obj.w };
- }
-}
diff --git a/components/WhiteBoard/ToolSelector/index.tsx b/components/WhiteBoard/ToolSelector/index.tsx
index 43ee312..dd9f603 100644
--- a/components/WhiteBoard/ToolSelector/index.tsx
+++ b/components/WhiteBoard/ToolSelector/index.tsx
@@ -4,34 +4,80 @@ import styles from './toolSelector.module.css';
import 'material-symbols';
export default function ToolSelector() {
+ const { currentTool, setCurrentTool } = useWhiteBoard((state) => ({
+ currentTool: state.currentTool,
+ setCurrentTool: state.setCurrentTool,
+ }));
return (
-
-
-
-
-
+
+
+
+
+
+
);
}
interface ToolButtonProps {
+ currentTool: Tool;
+ setCurrentTool: (tool: Tool) => void;
toolName: Tool;
icon: string;
}
-function ToolButton({ toolName, icon }: ToolButtonProps) {
- const { currentTool, setCurrentTool } = useWhiteBoard((state) => ({
- currentTool: state.currentTool,
- setCurrentTool: state.setCurrentTool,
- }));
+export function ToolButton({ currentTool, setCurrentTool, toolName, icon }: ToolButtonProps) {
+ return (
+ setCurrentTool(toolName)}
+ />
+ );
+}
+interface SmallIconButtonProps {
+ icon: string;
+ selected: boolean;
+ onClick?: () => void;
+}
+
+export function SmallIconButton({ icon, selected, onClick }: SmallIconButtonProps) {
return (
setCurrentTool(toolName)}
+ className={`${styles.buttonContainer} ${selected ? styles.buttonSelection : ''}`}
+ onClick={onClick}
>
{icon}
diff --git a/components/WhiteBoard/ToolSelector/toolSelector.module.css b/components/WhiteBoard/ToolSelector/toolSelector.module.css
index 77ea04c..fac1a1b 100644
--- a/components/WhiteBoard/ToolSelector/toolSelector.module.css
+++ b/components/WhiteBoard/ToolSelector/toolSelector.module.css
@@ -16,8 +16,9 @@
align-items: center;
border-radius: 50%;
cursor: default;
- width: 33px;
- height: 33px;
+ min-width: 33px;
+ min-height: 33px;
+ flex: 0;
color: var(--background);
background-color: transparent;
}
diff --git a/components/WhiteBoard/TreeViewer/index.tsx b/components/WhiteBoard/TreeViewer/index.tsx
index a245044..2cd8c3f 100644
--- a/components/WhiteBoard/TreeViewer/index.tsx
+++ b/components/WhiteBoard/TreeViewer/index.tsx
@@ -85,5 +85,7 @@ function typeToIcon(type: ObjType) {
return 'dashboard';
case 'LINE':
return 'linear_scale';
+ case 'CIRCLE':
+ return 'circle';
}
}
diff --git a/components/WhiteBoard/index.tsx b/components/WhiteBoard/index.tsx
index 065db4d..60a02aa 100644
--- a/components/WhiteBoard/index.tsx
+++ b/components/WhiteBoard/index.tsx
@@ -16,7 +16,7 @@ export default function WhiteBoard({ style }: WhiteBoardProps) {
flat
frameloop="demand"
style={style}
- camera={{ position: [0, 0, 100], zoom: 1 }}
+ camera={{ position: [0, 0, 100], zoom: 1, far: 1000000, near: 0 }}
orthographic
>
diff --git a/global.d.ts b/global.d.ts
index 6221475..2395610 100644
--- a/global.d.ts
+++ b/global.d.ts
@@ -4,7 +4,15 @@ interface ObjNode {
depth: number;
}
-type ObjType = 'RECT' | 'TEXT' | 'ROOT' | 'LINE';
+type ObjType =
+ | 'RECT'
+ | 'TEXT'
+ | 'ROOT'
+ | 'LINE'
+ | 'CIRCLE'
+ | 'GRAPHROOT'
+ | 'LIVEGRAPH'
+ | 'GRAPHNODE';
interface Obj {
objId: string;
@@ -22,7 +30,52 @@ interface ObjDimensions {
h: number;
}
+interface LiveGraphObj extends Obj {
+ type: 'LIVEGRAPH';
+ data: MindmapResponse;
+}
+
+interface GraphNodeObj extends Obj {
+ type: 'GRAPHNODE';
+ label: string;
+}
+
+interface GraphRootObj extends GraphNodeObj {
+ type: 'GRAPHROOT';
+}
+
+interface CircleObj extends Obj {
+ type: 'CIRCLE';
+ r: number;
+ color: string;
+}
+
+interface CircleOptions {
+ color?: string;
+}
+
+interface GraphData {
+ nodes: NodeData[];
+ links: LinkData[];
+}
+
+interface NodeData {
+ id: string;
+ name: string;
+ val: number;
+ color: string;
+ r: number;
+ __threeObj?: Mesh;
+}
+
+interface LinkData {
+ source: string;
+ target: string;
+ color: string;
+}
+
interface RectObj extends Obj {
+ type: 'RECT';
w: number;
h: number;
color: string;
@@ -31,6 +84,7 @@ interface RectObj extends Obj {
type OverflowType = 'normal' | 'break-word';
type TextAlgin = 'center' | 'left' | 'right';
interface TextObj extends Obj {
+ type: 'TEXT';
w: number;
fontSize: number;
overflow: OverflowType;
@@ -48,6 +102,7 @@ interface TextOptions {
}
interface LineObj extends Obj {
+ type: 'LINE';
x2: number;
y2: number;
color: string;
@@ -64,11 +119,12 @@ interface Coord {
y: number;
}
-type Tool = 'HAND' | 'SELECT' | 'RECT' | 'TEXT' | 'LINE' | 'BUNDLE';
+type Tool = 'HAND' | 'SELECT' | 'RECT' | 'TEXT' | 'LINE' | 'BUNDLE' | 'CIRCLE' | 'HIGHLIGHT';
interface WBDocumentMetadata {
documentId: number;
documentName: string;
+ data: WBSourceData;
createdAt: number;
modifiedAt: number;
}
@@ -111,6 +167,13 @@ interface MindmapResponse {
graph: Map;
}
+type WBSourceDataType = 'pdf' | 'audio';
+
+interface WBSourceData {
+ type: WBSourceDataType;
+ url: string;
+}
+
interface ObjBundle {
x: number;
y: number;
diff --git a/next.config.js b/next.config.js
index 658404a..949f771 100644
--- a/next.config.js
+++ b/next.config.js
@@ -1,4 +1,9 @@
/** @type {import('next').NextConfig} */
-const nextConfig = {};
+const nextConfig = {
+ webpack: (config) => {
+ config.resolve.alias.canvas = false;
+ return config;
+ },
+};
module.exports = nextConfig;
diff --git a/package.json b/package.json
index 3b86252..632a503 100644
--- a/package.json
+++ b/package.json
@@ -15,15 +15,19 @@
"@types/node": "20.4.2",
"@types/react": "18.2.14",
"@types/react-dom": "18.2.7",
+ "@types/react-pdf": "^7.0.0",
"@types/three": "^0.154.0",
"d3": "^7.8.5",
+ "d3-force-3d": "^3.0.5",
"eslint": "8.44.0",
"eslint-config-next": "13.4.9",
"material-symbols": "^0.10.1",
"next": "^13.4.12",
"react": "18.2.0",
"react-dom": "18.2.0",
+ "react-pdf": "^7.5.0",
"three": "^0.154.0",
+ "three-forcegraph": "^1.41.10",
"typescript": "5.1.6",
"zustand": "^4.4.0"
},
diff --git a/states/whiteboard.ts b/states/whiteboard.ts
index 5ebc653..e9a18b2 100644
--- a/states/whiteboard.ts
+++ b/states/whiteboard.ts
@@ -12,13 +12,15 @@ interface WhiteBoardState {
interface WhiteBoardActions {
addBundle: (offset: Coord) => void;
- addObj: (obj: Obj) => void;
+ addObj: (obj: Obj, global?: boolean) => void;
updateObj: (obj: Obj) => void;
+ syncObjTree: () => void;
setCurrentTool: (tool: Tool) => void;
setCurrentObj: (obj: string | null) => void;
setDrag: (drag: DragData | null) => void;
loadDocument: (document: WBDocument) => void;
setBundle: (bundle: ObjBundle) => void;
+ removeObj: (obj: Obj, global?: boolean) => void;
resetWhiteBoard: () => void;
}
@@ -38,19 +40,27 @@ const initialState = {
export const useWhiteBoard = create()((set, get) => ({
...initialState,
- addObj: (obj: Obj) =>
+ addObj: (obj: Obj, global: boolean = true) => {
set((state) => ({
objMap: state.objMap.set(obj.objId, obj),
- objTree: {
- ...state.objTree,
- childNodes: [
- { objId: obj.objId, childNodes: [], depth: obj.depth },
- ...state.objTree.childNodes,
- ],
- },
- currentObj: obj.objId,
- })),
+ }));
+ if (global) {
+ set((state) => ({
+ objTree: {
+ ...state.objTree,
+ childNodes: [
+ { objId: obj.objId, childNodes: [], depth: obj.depth },
+ ...state.objTree.childNodes,
+ ],
+ },
+ currentObj: obj.objId,
+ }));
+ }
+ },
updateObj: (obj: Obj) => set((state) => ({ objMap: state.objMap.set(obj.objId, obj) })),
+ syncObjTree: () => {
+ set({ objTree: constructRootObjTree(get().objMap) });
+ },
setCurrentTool: (tool: Tool) => set(() => ({ currentTool: tool })),
setCurrentObj: (obj: string | null) => set(() => ({ currentObj: obj })),
setDrag: (drag: DragData | null) => set(() => ({ drag: drag })),
@@ -78,4 +88,14 @@ export const useWhiteBoard = create()((set,
bundle: null,
}));
},
+ removeObj: (obj: Obj, global: boolean = true) => {
+ set((state) => {
+ const map = new Map(state.objMap);
+ map.delete(obj.objId);
+ return { objMap: map };
+ });
+ if (global) {
+ // TODO: remove from objTree
+ }
+ },
}));
diff --git a/utils/http.ts b/utils/http.ts
index c68c4d1..0bcc35a 100644
--- a/utils/http.ts
+++ b/utils/http.ts
@@ -38,7 +38,6 @@ export async function httpDelete(url: string, retry: boolean = true) {
function createHeaders() {
const accessToken = useUser.getState().accessToken;
const headers = new Headers();
- headers.set('ngrok-skip-browser-warning', 'fuck you');
if (accessToken.length > 0) headers.set('Authorization', accessToken);
return headers;
}
diff --git a/utils/whiteboardHelper.ts b/utils/whiteboardHelper.ts
index 03a53b6..13d138d 100644
--- a/utils/whiteboardHelper.ts
+++ b/utils/whiteboardHelper.ts
@@ -4,8 +4,9 @@ import {
forceCollide,
forceLink,
forceManyBody,
- forceRadial,
forceSimulation,
+ hierarchy,
+ tree,
} from 'd3';
import { Camera, Vector2, Vector3 } from 'three';
@@ -28,6 +29,8 @@ export const rootObj: Obj = {
parentId: '',
};
+export const DEFAULT_FONT = 'https://fonts.gstatic.com/ea/notosanskr/v2/NotoSansKR-Regular.woff';
+
/**
* Generate object id
*
@@ -58,7 +61,6 @@ export function genDepth(objA?: Obj, objB?: Obj): number {
* @return {number} Generated depth value.
*/
export function topDepth(): number {
- console.log(useWhiteBoard.getState().objTree);
const rootObjNode = useWhiteBoard.getState().objTree;
if (rootObjNode.childNodes.length === 0) {
return 0.0001;
@@ -144,6 +146,25 @@ export function createText(
} as TextObj);
}
+export function createCircle(
+ x: number,
+ y: number,
+ r: number,
+ depth: number = genDepth(),
+ options?: CircleOptions,
+): CircleObj {
+ return validateCircleObj({
+ objId: genId(),
+ type: 'CIRCLE',
+ x: x,
+ y: y,
+ r: r,
+ depth: depth,
+ parentId: 'ROOT',
+ color: options?.color ?? genColor(),
+ } as CircleObj);
+}
+
/**
* Create Line Object based on input parameter
*
@@ -296,6 +317,13 @@ function validateLineObj(obj: LineObj): LineObj {
return obj;
}
+function validateCircleObj(obj: CircleObj): CircleObj {
+ obj.x = validateValue(obj.x);
+ obj.y = validateValue(obj.y);
+ obj.r = validateValue(obj.r);
+ return obj;
+}
+
/**
* validates input text obj
*
@@ -336,11 +364,76 @@ interface LinkData {
target: number;
}
+export function createTreeFromMindmap(response: MindmapResponse): ObjBundle {
+ let top = topDepth();
+ const fontSize = 30;
+ const edgeColor = '#dddddd';
+ const fontColor = '#000000';
+ const nodeColor = '#000000';
+ const unit = 0.0001;
+ const result: Obj[] = [];
+ const bounds = { minX: NaN, maxX: NaN, minY: NaN, maxY: NaN };
+
+ const updateBounds = (obj: Obj) => {
+ if (isNaN(bounds.minX)) {
+ bounds.minX = obj.x;
+ bounds.maxX = obj.x;
+ bounds.minY = obj.y;
+ bounds.maxY = obj.y;
+ return;
+ }
+ bounds.minX = Math.min(bounds.minX, obj.x);
+ bounds.maxX = Math.max(bounds.maxX, obj.x);
+ bounds.minY = Math.min(bounds.minY, obj.y);
+ bounds.maxY = Math.max(bounds.maxY, obj.y);
+ };
+
+ const appendObj = (obj: Obj) => {
+ updateBounds(obj);
+ result.push(obj);
+ top += unit;
+ };
+
+ const graph = new Map(Object.entries(response.graph));
+ const root = hierarchy(response.root as unknown, (d) => {
+ return graph.get((d as number).toString());
+ });
+
+ const pointRadius = 5;
+
+ const layout = tree().nodeSize([60, 300]);
+ const data = layout(root);
+
+ data.links().map((v) => {
+ appendObj(
+ createLine(v.source.y, v.source.x, v.target.y, v.target.x, top, { color: edgeColor }),
+ );
+ });
+ data.descendants().map((v) => {
+ appendObj(
+ createText(v.y - 50, v.x + pointRadius * 2 + 5, 100, top, {
+ color: fontColor,
+ fontSize: fontSize,
+ text: response.keywords[v.data as number],
+ textAlign: 'center',
+ }),
+ );
+ appendObj(
+ createCircle(v.y - pointRadius, v.x - pointRadius, pointRadius, top, { color: nodeColor }),
+ );
+ });
+ return {
+ x: validateValue((bounds.maxX + bounds.minX) / 2),
+ y: validateValue((bounds.maxY + bounds.minY) / 2),
+ w: bounds.maxX - bounds.minX,
+ h: bounds.maxY - bounds.minY,
+ objs: result,
+ };
+}
+
export function createForceBundleFromMindmap(response: MindmapResponse): ObjBundle {
const fontSize = 20;
- const nodeWidth = fontSize * 8;
- const nodeHeight = fontSize * 2;
- const radius = nodeWidth / 2 + 10;
+ const radius = 50;
const edgeWidth = 2;
const edgeColor = '#31493C';
const fontColor = '#FFFFFF';
@@ -396,13 +489,11 @@ export function createForceBundleFromMindmap(response: MindmapResponse): ObjBund
'link',
forceLink(links)
.id((d) => d.id)
- .strength(2)
- .distance(10),
+ .strength(2),
)
.force('charge', forceManyBody().strength(-100))
.force('center', forceCenter(0, 0).strength(1))
- .force('collision', forceCollide(radius))
- .force('radial', forceRadial(0, 0, 100))
+ .force('collision', forceCollide(radius * 2))
.tick(300);
for (const link of links) {
@@ -418,21 +509,22 @@ export function createForceBundleFromMindmap(response: MindmapResponse): ObjBund
for (const node of nodes) {
appendObj(
- createRect(
- (node.x ?? 0) - nodeWidth / 2,
- (node.y ?? 0) - nodeHeight / 2,
- nodeWidth,
- nodeHeight,
- nodeColor,
+ createCircle(
+ (node.x ?? 0) - radius,
+ (node.y ?? 0) - radius,
+ radius,
+
top,
+ { color: nodeColor },
),
);
appendObj(
- createText((node.x ?? 0) - nodeWidth / 2, (node.y ?? 0) - fontSize / 2, nodeWidth, top, {
+ createText((node.x ?? 0) - radius, (node.y ?? 0) - fontSize / 2, radius * 2, top, {
textAlign: 'center',
fontSize: fontSize,
text: node.label,
color: fontColor,
+ overflow: 'break-word',
}),
);
}
@@ -446,6 +538,12 @@ export function createForceBundleFromMindmap(response: MindmapResponse): ObjBund
};
}
+export function calculateLineGeometry(x: number, y: number, x2: number, y2: number) {
+ const w = Math.sqrt(Math.pow(x - x2, 2) + Math.pow(y - y2, 2));
+ const d = Math.atan2(y2 - y, x2 - x);
+ return { w, d };
+}
+
// DAGRE.js tree version
//
// export function createTreeBundleFromMindmap(response: MindmapResponse): ObjBundle {
@@ -547,6 +645,7 @@ export function translateObj(obj: Obj, offset: Coord): Obj {
(obj as LineObj).y2 = validateValue((obj as LineObj).y2 + offset.y);
case 'RECT':
case 'TEXT':
+ case 'CIRCLE':
obj.x = validateValue(obj.x + offset.x);
obj.y = validateValue(obj.y + offset.y);
}
diff --git a/yarn.lock b/yarn.lock
index f5bfc28..ee51177 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -92,6 +92,21 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
+"@mapbox/node-pre-gyp@^1.0.0":
+ version "1.0.11"
+ resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz#417db42b7f5323d79e93b34a6d7a2a12c0df43fa"
+ integrity sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==
+ dependencies:
+ detect-libc "^2.0.0"
+ https-proxy-agent "^5.0.0"
+ make-dir "^3.1.0"
+ node-fetch "^2.6.7"
+ nopt "^5.0.0"
+ npmlog "^5.0.1"
+ rimraf "^3.0.2"
+ semver "^7.3.5"
+ tar "^6.1.11"
+
"@mediapipe/tasks-vision@0.10.2-rc2":
version "0.10.2-rc2"
resolved "https://registry.yarnpkg.com/@mediapipe/tasks-vision/-/tasks-vision-0.10.2-rc2.tgz#e3fa5d84d58b9031a0e975d1e5ef8eb8e4a6fc11"
@@ -292,28 +307,28 @@
integrity sha512-lB9lMjuqjtuJrx7/kOkqQBtllspPIN+96OvTCeJ2j5FEzinoAXTdAMFnDAQT1KVPRlnYfBrqxtqP66vDM40xxQ==
"@types/d3-array@*":
- version "3.0.5"
- resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-3.0.5.tgz#857c1afffd3f51319bbc5b301956aca68acaa7b8"
- integrity sha512-Qk7fpJ6qFp+26VeQ47WY0mkwXaiq8+76RJcncDEfMc2ocRzXLO67bLFRNI4OX1aGBoPzsM5Y2T+/m1pldOgD+A==
+ version "3.0.7"
+ resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-3.0.7.tgz#b128a0c0b0d9481d3281df47de0955730db384a1"
+ integrity sha512-4/Q0FckQ8TBjsB0VdGFemJOG8BLXUB2KKlL0VmZ+eOYeOnTb/wDRQqYWpBmQ6IlvWkXwkYiot+n9Px2aTJ7zGQ==
"@types/d3-axis@*":
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/@types/d3-axis/-/d3-axis-3.0.2.tgz#96e11d51256baf5bdb2fa73a17d302993e79df07"
- integrity sha512-uGC7DBh0TZrU/LY43Fd8Qr+2ja1FKmH07q2FoZFHo1eYl8aj87GhfVoY1saJVJiq24rp1+wpI6BvQJMKgQm8oA==
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@types/d3-axis/-/d3-axis-3.0.3.tgz#e9ca5d1dd7b1da4023ab0f9e921c3f6e86b8c06d"
+ integrity sha512-SE3x/pLO/+GIHH17mvs1uUVPkZ3bHquGzvZpPAh4yadRy71J93MJBpgK/xY8l9gT28yTN1g9v3HfGSFeBMmwZw==
dependencies:
"@types/d3-selection" "*"
"@types/d3-brush@*":
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/@types/d3-brush/-/d3-brush-3.0.2.tgz#a610aad5a1e76c375be63e11c5eee1ed9fd2fb40"
- integrity sha512-2TEm8KzUG3N7z0TrSKPmbxByBx54M+S9lHoP2J55QuLU0VSQ9mE96EJSAOVNEqd1bbynMjeTS9VHmz8/bSw8rA==
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@types/d3-brush/-/d3-brush-3.0.3.tgz#c5de3fd8efad6d85507fa74992540060aba38c25"
+ integrity sha512-MQ1/M/B5ifTScHSe5koNkhxn2mhUPqXjGuKjjVYckplAPjP9t2I2sZafb/YVHDwhoXWZoSav+Q726eIbN3qprA==
dependencies:
"@types/d3-selection" "*"
"@types/d3-chord@*":
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/@types/d3-chord/-/d3-chord-3.0.2.tgz#cf6f05ad2d8faaad524e9e6f454b4fd06b200930"
- integrity sha512-abT/iLHD3sGZwqMTX1TYCMEulr+wBd0SzyOQnjYNLp7sngdOHYtNkMRI5v3w5thoN+BWtlHVDx2Osvq6fxhZWw==
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@types/d3-chord/-/d3-chord-3.0.3.tgz#cd1dc38ac7cb390fe06abc09d30ddf0cd2ff350a"
+ integrity sha512-keuSRwO02c7PBV3JMWuctIfdeJrVFI7RpzouehvBWL4/GGUB3PBNg/9ZKPZAgJphzmS2v2+7vr7BGDQw1CAulw==
"@types/d3-color@*":
version "3.1.0"
@@ -321,9 +336,9 @@
integrity sha512-HKuicPHJuvPgCD+np6Se9MQvS6OCbJmOjGvylzMJRlDwUXjKTTXs6Pwgk79O09Vj/ho3u1ofXnhFOaEWWPrlwA==
"@types/d3-contour@*":
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/@types/d3-contour/-/d3-contour-3.0.2.tgz#d8a0e4d12ec14f7d2bb6e59f3fbc1a527457d0b2"
- integrity sha512-k6/bGDoAGJZnZWaKzeB+9glgXCYGvh6YlluxzBREiVo8f/X2vpTEdgPy9DN7Z2i42PZOZ4JDhVdlTSTSkLDPlQ==
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@types/d3-contour/-/d3-contour-3.0.3.tgz#16255aeb85557488bdf84c0a7988c428c0d2939b"
+ integrity sha512-x7G/tdDZt4m09XZnG2SutbIuQqmkNYqR9uhDMdPlpJbcwepkEjEWG29euFcgVA1k6cn92CHdDL9Z+fOnxnbVQw==
dependencies:
"@types/d3-array" "*"
"@types/geojson" "*"
@@ -334,21 +349,21 @@
integrity sha512-tLxQ2sfT0p6sxdG75c6f/ekqxjyYR0+LwPrsO1mbC9YDBzPJhs2HbJJRrn8Ez1DBoHRo2yx7YEATI+8V1nGMnQ==
"@types/d3-dispatch@*":
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/@types/d3-dispatch/-/d3-dispatch-3.0.2.tgz#b2fa80bab3bcead68680766e966f59cd6cb9a69f"
- integrity sha512-rxN6sHUXEZYCKV05MEh4z4WpPSqIw+aP7n9ZN6WYAAvZoEAghEK1WeVZMZcHRBwyaKflU43PCUAJNjFxCzPDjg==
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@types/d3-dispatch/-/d3-dispatch-3.0.3.tgz#5f6a4e9bbf90e8f775083154c3d7205cfb804762"
+ integrity sha512-Df7KW3Re7G6cIpIhQtqHin8yUxUHYAqiE41ffopbmU5+FifYUNV7RVyTg8rQdkEagg83m14QtS8InvNb95Zqug==
"@types/d3-drag@*":
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/@types/d3-drag/-/d3-drag-3.0.2.tgz#5562da3e7b33d782c2c1f9e65c5e91bb01ee82cf"
- integrity sha512-qmODKEDvyKWVHcWWCOVcuVcOwikLVsyc4q4EBJMREsoQnR2Qoc2cZQUyFUPgO9q4S3qdSqJKBsuefv+h0Qy+tw==
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@types/d3-drag/-/d3-drag-3.0.3.tgz#829a58420d8818be65a005795068964ff80a387b"
+ integrity sha512-82AuQMpBQjuXeIX4tjCYfWjpm3g7aGCfx6dFlxX2JlRaiME/QWcHzBsINl7gbHCODA2anPYlL31/Trj/UnjK9A==
dependencies:
"@types/d3-selection" "*"
"@types/d3-dsv@*":
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/@types/d3-dsv/-/d3-dsv-3.0.1.tgz#c51a3505cee42653454b74a00f8713dc3548c362"
- integrity sha512-76pBHCMTvPLt44wFOieouXcGXWOF0AJCceUvaFkxSZEu4VDUdv93JfpMa6VGNFs01FHfuP4a5Ou68eRG1KBfTw==
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/@types/d3-dsv/-/d3-dsv-3.0.2.tgz#0504c17388714e28a601dcaaf400147271ea14c2"
+ integrity sha512-DooW5AOkj4AGmseVvbwHvwM/Ltu0Ks0WrhG6r5FG9riHT5oUUTHz6xHsHqJSVU8ZmPkOqlUEY2obS5C9oCIi2g==
"@types/d3-ease@*":
version "3.0.0"
@@ -356,16 +371,16 @@
integrity sha512-aMo4eaAOijJjA6uU+GIeW018dvy9+oH5Y2VPPzjjfxevvGQ/oRDs+tfYC9b50Q4BygRR8yE2QCLsrT0WtAVseA==
"@types/d3-fetch@*":
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/@types/d3-fetch/-/d3-fetch-3.0.2.tgz#fe1f335243e07c9bd520c9a71756fed8330c54b1"
- integrity sha512-gllwYWozWfbep16N9fByNBDTkJW/SyhH6SGRlXloR7WdtAaBui4plTP+gbUgiEot7vGw/ZZop1yDZlgXXSuzjA==
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@types/d3-fetch/-/d3-fetch-3.0.3.tgz#ae55cc49bd71b448182deff0cc4b448eff1f9b33"
+ integrity sha512-/EsDKRiQkby3Z/8/AiZq8bsuLDo/tYHnNIZkUpSeEHWV7fHUl6QFBjvMPbhkKGk9jZutzfOkGygCV7eR/MkcXA==
dependencies:
"@types/d3-dsv" "*"
"@types/d3-force@*":
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/@types/d3-force/-/d3-force-3.0.4.tgz#2d50bd2b695f709797e1745644f6bc123e6e5f5a"
- integrity sha512-q7xbVLrWcXvSBBEoadowIUJ7sRpS1yvgMWnzHJggFy5cUZBq2HZL5k/pBSm0GdYWS1vs5/EDwMjSKF55PDY4Aw==
+ version "3.0.5"
+ resolved "https://registry.yarnpkg.com/@types/d3-force/-/d3-force-3.0.5.tgz#835bbe01e084195175ddf71b7900bd44a9a23e8e"
+ integrity sha512-EGG+IWx93ESSXBwfh/5uPuR9Hp8M6o6qEGU7bBQslxCvrdUBQZha/EFpu/VMdLU4B0y4Oe4h175nSm7p9uqFug==
"@types/d3-format@*":
version "3.0.1"
@@ -373,16 +388,16 @@
integrity sha512-5KY70ifCCzorkLuIkDe0Z9YTf9RR2CjBX1iaJG+rgM/cPP+sO+q9YdQ9WdhQcgPj1EQiJ2/0+yUkkziTG6Lubg==
"@types/d3-geo@*":
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/@types/d3-geo/-/d3-geo-3.0.3.tgz#535e5f24be13722964c52354301be09b752f5d6e"
- integrity sha512-bK9uZJS3vuDCNeeXQ4z3u0E7OeJZXjUgzFdSOtNtMCJCLvDtWDwfpRVWlyt3y8EvRzI0ccOu9xlMVirawolSCw==
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/@types/d3-geo/-/d3-geo-3.0.4.tgz#fa38f02256c3023ea3b88cb011cff1426eb7ff52"
+ integrity sha512-kmUK8rVVIBPKJ1/v36bk2aSgwRj2N/ZkjDT+FkMT5pgedZoPlyhaG62J+9EgNIgUXE6IIL0b7bkLxCzhE6U4VQ==
dependencies:
"@types/geojson" "*"
"@types/d3-hierarchy@*":
- version "3.1.2"
- resolved "https://registry.yarnpkg.com/@types/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz#b3a446b5437faededb30ac32b7cc0486559ab1e2"
- integrity sha512-9hjRTVoZjRFR6xo8igAJyNXQyPX6Aq++Nhb5ebrUF414dv4jr2MitM2fWiOY475wa3Za7TOS2Gh9fmqEhLTt0A==
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/@types/d3-hierarchy/-/d3-hierarchy-3.1.3.tgz#9e935540e2494f3402938bf53811ed74ca3c36ba"
+ integrity sha512-GpSK308Xj+HeLvogfEc7QsCOcIxkDwLhFYnOoohosEzOqv7/agxwvJER1v/kTC+CY1nfazR0F7gnHo7GE41/fw==
"@types/d3-interpolate@*":
version "3.0.1"
@@ -417,21 +432,21 @@
integrity sha512-dsoJGEIShosKVRBZB0Vo3C8nqSDqVGujJU6tPznsBJxNJNwMF8utmS83nvCBKQYPpjCzaaHcrf66iTRpZosLPw==
"@types/d3-scale@*":
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-4.0.3.tgz#7a5780e934e52b6f63ad9c24b105e33dd58102b5"
- integrity sha512-PATBiMCpvHJSMtZAMEhc2WyL+hnzarKzI6wAHYjhsonjWJYGq5BXTzQjv4l8m2jO183/4wZ90rKvSeT7o72xNQ==
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-4.0.4.tgz#3c5e2263eea5a3670cd91043b9f4d150a94c43f1"
+ integrity sha512-eq1ZeTj0yr72L8MQk6N6heP603ubnywSDRfNpi5enouR112HzGLS6RIvExCzZTraFF4HdzNpJMwA/zGiMoHUUw==
dependencies:
"@types/d3-time" "*"
"@types/d3-selection@*":
- version "3.0.5"
- resolved "https://registry.yarnpkg.com/@types/d3-selection/-/d3-selection-3.0.5.tgz#27cd53b7672d405025e2414d98532d7934c16ebd"
- integrity sha512-xCB0z3Hi8eFIqyja3vW8iV01+OHGYR2di/+e+AiOcXIOrY82lcvWW8Ke1DYE/EUVMsBl4Db9RppSBS3X1U6J0w==
+ version "3.0.6"
+ resolved "https://registry.yarnpkg.com/@types/d3-selection/-/d3-selection-3.0.6.tgz#c35b5320188e921d10f77f50198705a14b8aecf6"
+ integrity sha512-2ACr96USZVjXR9KMD9IWi1Epo4rSDKnUtYn6q2SPhYxykvXTw9vR77lkFNruXVg4i1tzQtBxeDMx0oNvJWbF1w==
"@types/d3-shape@*":
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/@types/d3-shape/-/d3-shape-3.1.1.tgz#15cc497751dac31192d7aef4e67a8d2c62354b95"
- integrity sha512-6Uh86YFF7LGg4PQkuO2oG6EMBRLuW9cbavUW46zkIO5kuS2PfTqo2o9SkgtQzguBHbLgNnU90UNsITpsX1My+A==
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/@types/d3-shape/-/d3-shape-3.1.2.tgz#a3d421d8b0bc0c6c67cb3f4b4471ddc133cb0117"
+ integrity sha512-NN4CXr3qeOUNyK5WasVUV8NCSAx/CRVcwcb0BuuS1PiTqwIm6ABi1SyasLZ/vsVCFDArF+W4QiGzSry1eKYQ7w==
dependencies:
"@types/d3-path" "*"
@@ -451,16 +466,16 @@
integrity sha512-HNB/9GHqu7Fo8AQiugyJbv6ZxYz58wef0esl4Mv828w1ZKpAshw/uFWVDUcIB9KKFeFKoxS3cHY07FFgtTRZ1g==
"@types/d3-transition@*":
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/@types/d3-transition/-/d3-transition-3.0.3.tgz#d4ac37d08703fb039c87f92851a598ba77400402"
- integrity sha512-/S90Od8Id1wgQNvIA8iFv9jRhCiZcGhPd2qX0bKF/PS+y0W5CrXKgIiELd2CvG1mlQrWK/qlYh3VxicqG1ZvgA==
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/@types/d3-transition/-/d3-transition-3.0.4.tgz#1515cd38bdc6d84103d7b6ccb25acdb72b5dd095"
+ integrity sha512-512a4uCOjUzsebydItSXsHrPeQblCVk8IKjqCUmrlvBWkkVh3donTTxmURDo1YPwIVDh5YVwCAO6gR4sgimCPQ==
dependencies:
"@types/d3-selection" "*"
"@types/d3-zoom@*":
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/@types/d3-zoom/-/d3-zoom-3.0.3.tgz#5c29006a61ff7ca512fe21398c66ad95dd846674"
- integrity sha512-OWk1yYIIWcZ07+igN6BeoG6rqhnJ/pYe+R1qWFM2DtW49zsoSjgb9G5xB0ZXA8hh2jAzey1XuRmMSoXdKw8MDA==
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/@types/d3-zoom/-/d3-zoom-3.0.4.tgz#1c754cf9f3ac96c59e6d9372c4d49f09e3e6fce3"
+ integrity sha512-cqkuY1ah9ZQre2POqjSLcM8g40UVya/qwEUrNYP2/rCVljbmqKCVcv+ebvwhlI5azIbSEL7m+os6n+WlYA43aA==
dependencies:
"@types/d3-interpolate" "*"
"@types/d3-selection" "*"
@@ -538,6 +553,13 @@
dependencies:
"@types/react" "*"
+"@types/react-pdf@^7.0.0":
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/@types/react-pdf/-/react-pdf-7.0.0.tgz#75ddcfd4c7a7f5c3f9d96ec506d5cddeb1020fbf"
+ integrity sha512-G0a+5UiKk3AvEauBP/Js7r9kGZNW3iBbS6kXkH0foGSaKWR6K3ElTe7Y4tlolc2VKbM9udmMxpkbxh/dtR2wXA==
+ dependencies:
+ react-pdf "*"
+
"@types/react-reconciler@^0.26.7":
version "0.26.7"
resolved "https://registry.yarnpkg.com/@types/react-reconciler/-/react-reconciler-0.26.7.tgz#0c4643f30821ae057e401b0d9037e03e8e9b2a36"
@@ -644,6 +666,16 @@
dependencies:
"@use-gesture/core" "10.2.27"
+abbrev@1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
+ integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
+
+accessor-fn@1:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/accessor-fn/-/accessor-fn-1.5.0.tgz#9353e10194da404366657f47177cd9bcb4463ee7"
+ integrity sha512-dml7D96DY/K5lt4Ra2jMnpL9Bhw5HEGws4p1OAIxFFj9Utd/RxNfEO3T3f0QIWFNwQU7gNxH9snUfqF/zNkP/w==
+
acorn-jsx@^5.3.2:
version "5.3.2"
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
@@ -654,6 +686,13 @@ acorn@^8.9.0:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5"
integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==
+agent-base@6:
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
+ integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==
+ dependencies:
+ debug "4"
+
ajv@^6.10.0, ajv@^6.12.4:
version "6.12.6"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
@@ -676,6 +715,19 @@ ansi-styles@^4.1.0:
dependencies:
color-convert "^2.0.1"
+"aproba@^1.0.3 || ^2.0.0":
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc"
+ integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==
+
+are-we-there-yet@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c"
+ integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==
+ dependencies:
+ delegates "^1.0.0"
+ readable-stream "^3.6.0"
+
argparse@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
@@ -841,6 +893,15 @@ caniuse-lite@^1.0.30001406:
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001517.tgz#90fabae294215c3495807eb24fc809e11dc2f0a8"
integrity sha512-Vdhm5S11DaFVLlyiKu4hiUTkpZu+y1KA/rZZqVQfOD5YdDT/eQKlkt7NaE0WGOFgX32diqt9MiP9CAiFeRklaA==
+canvas@^2.11.2:
+ version "2.11.2"
+ resolved "https://registry.yarnpkg.com/canvas/-/canvas-2.11.2.tgz#553d87b1e0228c7ac0fc72887c3adbac4abbd860"
+ integrity sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==
+ dependencies:
+ "@mapbox/node-pre-gyp" "^1.0.0"
+ nan "^2.17.0"
+ simple-get "^3.0.3"
+
chalk@^4.0.0:
version "4.1.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
@@ -861,11 +922,21 @@ chevrotain@^10.1.2:
lodash "4.17.21"
regexp-to-ast "0.5.0"
+chownr@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece"
+ integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==
+
client-only@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1"
integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==
+clsx@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.0.0.tgz#12658f3fd98fafe62075595a5c30e43d18f3d00b"
+ integrity sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==
+
color-convert@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
@@ -878,6 +949,11 @@ color-name@~1.1.4:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+color-support@^1.1.2:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2"
+ integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==
+
commander@7:
version "7.2.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
@@ -888,6 +964,11 @@ concat-map@0.0.1:
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
+console-control-strings@^1.0.0, console-control-strings@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
+ integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==
+
cross-spawn@^7.0.2, cross-spawn@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
@@ -902,7 +983,7 @@ csstype@^3.0.2:
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b"
integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==
-"d3-array@2 - 3", "d3-array@2.10.0 - 3", "d3-array@2.5.0 - 3", d3-array@3, d3-array@^3.2.0:
+"d3-array@1 - 3", "d3-array@2 - 3", "d3-array@2.10.0 - 3", "d3-array@2.5.0 - 3", d3-array@3, d3-array@^3.2.0:
version "3.2.4"
resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-3.2.4.tgz#15fec33b237f97ac5d7c986dc77da273a8ed0bb5"
integrity sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==
@@ -914,6 +995,11 @@ d3-axis@3:
resolved "https://registry.yarnpkg.com/d3-axis/-/d3-axis-3.0.0.tgz#c42a4a13e8131d637b745fc2973824cfeaf93322"
integrity sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==
+d3-binarytree@1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/d3-binarytree/-/d3-binarytree-1.0.2.tgz#ed43ebc13c70fbabfdd62df17480bc5a425753cc"
+ integrity sha512-cElUNH+sHu95L04m92pG73t2MEJXKu+GeKUN1TJkFsu93E5W8E9Sc3kHEGJKgenGvj19m6upSn2EunvMgMD2Yw==
+
d3-brush@3:
version "3.0.0"
resolved "https://registry.yarnpkg.com/d3-brush/-/d3-brush-3.0.0.tgz#6f767c4ed8dcb79de7ede3e1c0f89e63ef64d31c"
@@ -985,6 +1071,17 @@ d3-fetch@3:
dependencies:
d3-dsv "1 - 3"
+"d3-force-3d@2 - 3", d3-force-3d@^3.0.5:
+ version "3.0.5"
+ resolved "https://registry.yarnpkg.com/d3-force-3d/-/d3-force-3d-3.0.5.tgz#9c8931b49acc3554f9110e128bc580cd3ab830f2"
+ integrity sha512-tdwhAhoTYZY/a6eo9nR7HP3xSW/C6XvJTbeRpR92nlPzH6OiE+4MliN9feuSFd0tPtEUo+191qOhCTWx3NYifg==
+ dependencies:
+ d3-binarytree "1"
+ d3-dispatch "1 - 3"
+ d3-octree "1"
+ d3-quadtree "1 - 3"
+ d3-timer "1 - 3"
+
d3-force@3:
version "3.0.0"
resolved "https://registry.yarnpkg.com/d3-force/-/d3-force-3.0.0.tgz#3e2ba1a61e70888fe3d9194e30d6d14eece155c4"
@@ -1018,6 +1115,11 @@ d3-hierarchy@3:
dependencies:
d3-color "1 - 3"
+d3-octree@1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/d3-octree/-/d3-octree-1.0.2.tgz#b39026b82701e45c7163e34ee056dc492035a017"
+ integrity sha512-Qxg4oirJrNXauiuC94uKMbgxwnhdda9xRLl9ihq45srlJ4Ga3CSgqGcAL8iW7N5CIv4Oz8x3E734ulxyvHPvwA==
+
"d3-path@1 - 3", d3-path@3, d3-path@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-3.1.0.tgz#22df939032fb5a71ae8b1800d61ddb7851c42526"
@@ -1038,7 +1140,7 @@ d3-random@3:
resolved "https://registry.yarnpkg.com/d3-random/-/d3-random-3.0.1.tgz#d4926378d333d9c0bfd1e6fa0194d30aebaa20f4"
integrity sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==
-d3-scale-chromatic@3:
+"d3-scale-chromatic@1 - 3", d3-scale-chromatic@3:
version "3.0.0"
resolved "https://registry.yarnpkg.com/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz#15b4ceb8ca2bb0dcb6d1a641ee03d59c3b62376a"
integrity sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==
@@ -1046,7 +1148,7 @@ d3-scale-chromatic@3:
d3-color "1 - 3"
d3-interpolate "1 - 3"
-d3-scale@4:
+"d3-scale@1 - 4", d3-scale@4:
version "4.0.2"
resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-4.0.2.tgz#82b38e8e8ff7080764f8dcec77bd4be393689396"
integrity sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==
@@ -1151,11 +1253,25 @@ damerau-levenshtein@^1.0.8:
resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7"
integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==
+data-joint@1:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/data-joint/-/data-joint-1.3.1.tgz#d134950322c90f531e81bbbe8454277549031466"
+ integrity sha512-tMK0m4OVGqiA3zkn8JmO6YAqD8UwJqIAx4AAwFl1SKTtKAqcXePuT+n2aayiX9uITtlN3DFtKKTOxJRUc2+HvQ==
+ dependencies:
+ index-array-by "^1.4.0"
+
debounce@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5"
integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==
+debug@4, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
+ version "4.3.4"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
+ integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
+ dependencies:
+ ms "2.1.2"
+
debug@^3.2.7:
version "3.2.7"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
@@ -1163,12 +1279,12 @@ debug@^3.2.7:
dependencies:
ms "^2.1.1"
-debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
- version "4.3.4"
- resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
- integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
+decompress-response@^4.2.0:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-4.2.1.tgz#414023cc7a302da25ce2ec82d0d5238ccafd8986"
+ integrity sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==
dependencies:
- ms "2.1.2"
+ mimic-response "^2.0.0"
deep-is@^0.1.3:
version "0.1.4"
@@ -1213,6 +1329,11 @@ delaunator@5:
dependencies:
robust-predicates "^3.0.0"
+delegates@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
+ integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==
+
dequal@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be"
@@ -1225,6 +1346,11 @@ detect-gpu@^5.0.28:
dependencies:
webgl-constants "^1.1.1"
+detect-libc@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.2.tgz#8ccf2ba9315350e1241b88d0ac3b0e1fbd99605d"
+ integrity sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==
+
dir-glob@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
@@ -1251,6 +1377,11 @@ draco3d@^1.4.1:
resolved "https://registry.yarnpkg.com/draco3d/-/draco3d-1.5.6.tgz#0d570a9792e3a3a9fafbfea065b692940441c626"
integrity sha512-+3NaRjWktb5r61ZFoDejlykPEFKT5N/LkbXsaddlw6xNSXBanUYpFc2AXXpbJDilPHazcSreU/DpQIaxfX0NfQ==
+emoji-regex@^8.0.0:
+ version "8.0.0"
+ resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
+ integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
+
emoji-regex@^9.2.2:
version "9.2.2"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72"
@@ -1657,6 +1788,13 @@ for-each@^0.3.3:
dependencies:
is-callable "^1.1.3"
+fs-minipass@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb"
+ integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==
+ dependencies:
+ minipass "^3.0.0"
+
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
@@ -1682,6 +1820,21 @@ functions-have-names@^1.2.2, functions-have-names@^1.2.3:
resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834"
integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==
+gauge@^3.0.0:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395"
+ integrity sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==
+ dependencies:
+ aproba "^1.0.3 || ^2.0.0"
+ color-support "^1.1.2"
+ console-control-strings "^1.0.0"
+ has-unicode "^2.0.1"
+ object-assign "^4.1.1"
+ signal-exit "^3.0.0"
+ string-width "^4.2.3"
+ strip-ansi "^6.0.1"
+ wide-align "^1.1.2"
+
get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82"
@@ -1848,6 +2001,11 @@ has-tostringtag@^1.0.0:
dependencies:
has-symbols "^1.0.2"
+has-unicode@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
+ integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==
+
has@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
@@ -1855,6 +2013,14 @@ has@^1.0.3:
dependencies:
function-bind "^1.1.1"
+https-proxy-agent@^5.0.0:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6"
+ integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==
+ dependencies:
+ agent-base "6"
+ debug "4"
+
human-signals@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
@@ -1890,6 +2056,11 @@ imurmurhash@^0.1.4:
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==
+index-array-by@^1.4.0:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/index-array-by/-/index-array-by-1.4.1.tgz#425f26cf0c744a47ebadf47366692e52043cf17b"
+ integrity sha512-Zu6THdrxQdyTuT2uA5FjUoBEsFHPzHcPIj18FszN6yXKHxSfGcR4TPLabfuT//E25q1Igyx9xta2WMvD/x9P/g==
+
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
@@ -1898,7 +2069,7 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
-inherits@2:
+inherits@2, inherits@^2.0.3:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@@ -1975,6 +2146,11 @@ is-extglob@^2.1.1:
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
+is-fullwidth-code-point@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
+ integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
+
is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3:
version "4.0.3"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
@@ -2126,6 +2302,13 @@ json5@^1.0.2:
object.assign "^4.1.4"
object.values "^1.1.6"
+kapsule@1:
+ version "1.14.4"
+ resolved "https://registry.yarnpkg.com/kapsule/-/kapsule-1.14.4.tgz#55f19fe7a04dfe111e9efc7d85a895e6440ef828"
+ integrity sha512-Ro1US5B5mtyZMM+NqW/0fqcBf9oEO7fG0gYY9FY+BVGo4KaonVsplFfuYx3pZ/GLCQfYE5cONduILLktsYjUpQ==
+ dependencies:
+ lodash-es "4"
+
ktx-parse@^0.4.5:
version "0.4.5"
resolved "https://registry.yarnpkg.com/ktx-parse/-/ktx-parse-0.4.5.tgz#79905e22281a9d3e602b2ff522df1ee7d1813aa6"
@@ -2163,6 +2346,11 @@ locate-path@^6.0.0:
dependencies:
p-locate "^5.0.0"
+lodash-es@4:
+ version "4.17.21"
+ resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
+ integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
+
lodash.clamp@^4.0.3:
version "4.0.3"
resolved "https://registry.yarnpkg.com/lodash.clamp/-/lodash.clamp-4.0.3.tgz#5c24bedeeeef0753560dc2b4cb4671f90a6ddfaa"
@@ -2207,11 +2395,35 @@ maath@^0.6.0:
resolved "https://registry.yarnpkg.com/maath/-/maath-0.6.0.tgz#7841d0fb95bbb37d19b08b7c5458ef70190950d2"
integrity sha512-dSb2xQuP7vDnaYqfoKzlApeRcR2xtN8/f7WV/TMAkBC8552TwTLtOO0JTcSygkYMjNDPoo6V01jTw/aPi4JrMw==
+make-cancellable-promise@^1.3.1:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/make-cancellable-promise/-/make-cancellable-promise-1.3.1.tgz#3bd89704c75afe6251cdd6a82baca1fcfbd2c792"
+ integrity sha512-DWOzWdO3xhY5ESjVR+wVFy03rpt0ZccS4bunccNwngoX6rllKlMZm6S9ZnJ5nMuDDweqDMjtaO0g6tZeh+cCUA==
+
+make-dir@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
+ integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==
+ dependencies:
+ semver "^6.0.0"
+
+make-event-props@^1.6.0:
+ version "1.6.1"
+ resolved "https://registry.yarnpkg.com/make-event-props/-/make-event-props-1.6.1.tgz#1d587017c3f1f3b42719b775af93d5253656ccdd"
+ integrity sha512-JhvWq/iz1BvlmnPvLJjXv+xnMPJZuychrDC68V+yCGQJn5chcA8rLGKo5EP1XwIKVrigSXKLmbeXAGkf36wdCQ==
+
material-symbols@^0.10.1:
version "0.10.1"
resolved "https://registry.yarnpkg.com/material-symbols/-/material-symbols-0.10.1.tgz#a49cfce1a37079a70fd26b92f0e790b986072266"
integrity sha512-hGylDJScyjeR0LI524AVfCLI/thKuUX2rG78BYYHEg0R/IS4NzSh28aCP0k088968dxItxV/4hNNR4MAiXrb8Q==
+merge-refs@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/merge-refs/-/merge-refs-1.2.1.tgz#abddc800375395a4a4eb5c45ebf2a52557fdbe34"
+ integrity sha512-pRPz39HQz2xzHdXAGvtJ9S8aEpNgpUjzb5yPC3ytozodmsHg+9nqgRs7/YOmn9fM/TLzntAC8AdGTidKxOq9TQ==
+ dependencies:
+ "@types/react" "*"
+
merge-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
@@ -2250,6 +2462,11 @@ mimic-fn@^4.0.0:
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc"
integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==
+mimic-response@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-2.1.0.tgz#d13763d35f613d09ec37ebb30bac0469c0ee8f43"
+ integrity sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==
+
minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
@@ -2262,6 +2479,31 @@ minimist@^1.2.0, minimist@^1.2.6:
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
+minipass@^3.0.0:
+ version "3.3.6"
+ resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a"
+ integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==
+ dependencies:
+ yallist "^4.0.0"
+
+minipass@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d"
+ integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==
+
+minizlib@^2.1.1:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931"
+ integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==
+ dependencies:
+ minipass "^3.0.0"
+ yallist "^4.0.0"
+
+mkdirp@^1.0.3:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
+ integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
+
mmd-parser@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/mmd-parser/-/mmd-parser-1.0.4.tgz#87cc05782cb5974ca854f0303fc5147bc9d690e7"
@@ -2277,6 +2519,11 @@ ms@^2.1.1:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
+nan@^2.17.0:
+ version "2.18.0"
+ resolved "https://registry.yarnpkg.com/nan/-/nan-2.18.0.tgz#26a6faae7ffbeb293a39660e88a76b82e30b7554"
+ integrity sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==
+
nanoid@^3.3.4:
version "3.3.6"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c"
@@ -2311,6 +2558,51 @@ next@^13.4.12:
"@next/swc-win32-ia32-msvc" "13.4.12"
"@next/swc-win32-x64-msvc" "13.4.12"
+ngraph.events@^1.0.0, ngraph.events@^1.2.1:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/ngraph.events/-/ngraph.events-1.2.2.tgz#3ceb92d676a04a4e7ce60a09fa8e17a4f0346d7f"
+ integrity sha512-JsUbEOzANskax+WSYiAPETemLWYXmixuPAlmZmhIbIj6FH/WDgEGCGnRwUQBK0GjOnVm8Ui+e5IJ+5VZ4e32eQ==
+
+ngraph.forcelayout@3:
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/ngraph.forcelayout/-/ngraph.forcelayout-3.3.1.tgz#981e1baee5e0593c490bc27219169f9cedfa4f8b"
+ integrity sha512-MKBuEh1wujyQHFTW57y5vd/uuEOK0XfXYxm3lC7kktjJLRdt/KEKEknyOlc6tjXflqBKEuYBBcu7Ax5VY+S6aw==
+ dependencies:
+ ngraph.events "^1.0.0"
+ ngraph.merge "^1.0.0"
+ ngraph.random "^1.0.0"
+
+ngraph.graph@20:
+ version "20.0.1"
+ resolved "https://registry.yarnpkg.com/ngraph.graph/-/ngraph.graph-20.0.1.tgz#579470d1d805583239704dc913e2095540aaf371"
+ integrity sha512-VFsQ+EMkT+7lcJO1QP8Ik3w64WbHJl27Q53EO9hiFU9CRyxJ8HfcXtfWz/U8okuoYKDctbciL6pX3vG5dt1rYA==
+ dependencies:
+ ngraph.events "^1.2.1"
+
+ngraph.merge@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/ngraph.merge/-/ngraph.merge-1.0.0.tgz#d763cdfa48b1bbd4270ea246f06c9c8ff5d3477c"
+ integrity sha512-5J8YjGITUJeapsomtTALYsw7rFveYkM+lBj3QiYZ79EymQcuri65Nw3knQtFxQBU1r5iOaVRXrSwMENUPK62Vg==
+
+ngraph.random@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/ngraph.random/-/ngraph.random-1.1.0.tgz#5345c4bb63865c85d98ee6f13eab1395d8545a90"
+ integrity sha512-h25UdUN/g8U7y29TzQtRm/GvGr70lK37yQPvPKXXuVfs7gCm82WipYFZcksQfeKumtOemAzBIcT7lzzyK/edLw==
+
+node-fetch@^2.6.7:
+ version "2.7.0"
+ resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d"
+ integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==
+ dependencies:
+ whatwg-url "^5.0.0"
+
+nopt@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88"
+ integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==
+ dependencies:
+ abbrev "1"
+
npm-run-path@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"
@@ -2325,6 +2617,16 @@ npm-run-path@^5.1.0:
dependencies:
path-key "^4.0.0"
+npmlog@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0"
+ integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==
+ dependencies:
+ are-we-there-yet "^2.0.0"
+ console-control-strings "^1.1.0"
+ gauge "^3.0.0"
+ set-blocking "^2.0.0"
+
object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
@@ -2385,7 +2687,7 @@ object.values@^1.1.6:
define-properties "^1.1.4"
es-abstract "^1.20.4"
-once@^1.3.0:
+once@^1.3.0, once@^1.3.1:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
@@ -2487,6 +2789,19 @@ path-type@^4.0.0:
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
+path2d-polyfill@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/path2d-polyfill/-/path2d-polyfill-2.0.1.tgz#24c554a738f42700d6961992bf5f1049672f2391"
+ integrity sha512-ad/3bsalbbWhmBo0D6FZ4RNMwsLsPpL6gnvhuSaU5Vm7b06Kr5ubSltQQ0T7YKsiJQO+g22zJ4dJKNTXIyOXtA==
+
+pdfjs-dist@3.11.174:
+ version "3.11.174"
+ resolved "https://registry.yarnpkg.com/pdfjs-dist/-/pdfjs-dist-3.11.174.tgz#5ff47b80f2d58c8dd0d74f615e7c6a7e7e704c4b"
+ integrity sha512-TdTZPf1trZ8/UFu5Cx/GXB7GZM30LT+wWUNfsi6Bq8ePLnb+woNKtDymI2mxZYBpMbonNFqKmiz684DIfnd8dA==
+ optionalDependencies:
+ canvas "^2.11.2"
+ path2d-polyfill "^2.0.1"
+
picocolors@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
@@ -2516,7 +2831,7 @@ prelude-ls@^1.2.1:
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
-prop-types@^15.6.0, prop-types@^15.8.1:
+prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@@ -2560,6 +2875,20 @@ react-merge-refs@^1.1.0:
resolved "https://registry.yarnpkg.com/react-merge-refs/-/react-merge-refs-1.1.0.tgz#73d88b892c6c68cbb7a66e0800faa374f4c38b06"
integrity sha512-alTKsjEL0dKH/ru1Iyn7vliS2QRcBp9zZPGoWxUOvRGWPUYgjo+V01is7p04It6KhgrzhJGnIj9GgX8W4bZoCQ==
+react-pdf@*, react-pdf@^7.5.0:
+ version "7.5.0"
+ resolved "https://registry.yarnpkg.com/react-pdf/-/react-pdf-7.5.0.tgz#a49d51faf2a68e0bc30d5a8ff5335061bb72a4b1"
+ integrity sha512-hX7SfQGd9T6pdd3H5HcR1VzrRCehkhnBh/tsyz9GO9cXrYHgoxupboVL2VCQpBBSak+/UQSMCj+3JTOdheuwwQ==
+ dependencies:
+ clsx "^2.0.0"
+ make-cancellable-promise "^1.3.1"
+ make-event-props "^1.6.0"
+ merge-refs "^1.2.1"
+ pdfjs-dist "3.11.174"
+ prop-types "^15.6.2"
+ tiny-invariant "^1.0.0"
+ tiny-warning "^1.0.0"
+
react-reconciler@^0.27.0:
version "0.27.0"
resolved "https://registry.yarnpkg.com/react-reconciler/-/react-reconciler-0.27.0.tgz#360124fdf2d76447c7491ee5f0e04503ed9acf5b"
@@ -2582,6 +2911,15 @@ react@18.2.0:
dependencies:
loose-envify "^1.1.0"
+readable-stream@^3.6.0:
+ version "3.6.2"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967"
+ integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==
+ dependencies:
+ inherits "^2.0.3"
+ string_decoder "^1.1.1"
+ util-deprecate "^1.0.1"
+
regenerator-runtime@^0.13.11:
version "0.13.11"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9"
@@ -2670,6 +3008,11 @@ rw@1:
resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4"
integrity sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==
+safe-buffer@~5.2.0:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
+ integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
+
safe-regex-test@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295"
@@ -2698,18 +3041,23 @@ scheduler@^0.23.0:
dependencies:
loose-envify "^1.1.0"
-semver@^6.3.0:
+semver@^6.0.0, semver@^6.3.0:
version "6.3.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
-semver@^7.3.7:
+semver@^7.3.5, semver@^7.3.7:
version "7.5.4"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
dependencies:
lru-cache "^6.0.0"
+set-blocking@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
+ integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==
+
shebang-command@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
@@ -2731,11 +3079,25 @@ side-channel@^1.0.4:
get-intrinsic "^1.0.2"
object-inspect "^1.9.0"
-signal-exit@^3.0.3, signal-exit@^3.0.7:
+signal-exit@^3.0.0, signal-exit@^3.0.3, signal-exit@^3.0.7:
version "3.0.7"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
+simple-concat@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f"
+ integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==
+
+simple-get@^3.0.3:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-3.1.1.tgz#cc7ba77cfbe761036fbfce3d021af25fc5584d55"
+ integrity sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==
+ dependencies:
+ decompress-response "^4.2.0"
+ once "^1.3.1"
+ simple-concat "^1.0.0"
+
slash@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
@@ -2761,6 +3123,15 @@ streamsearch@^1.1.0:
resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764"
integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==
+"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.2.3:
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
+ integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
+ dependencies:
+ emoji-regex "^8.0.0"
+ is-fullwidth-code-point "^3.0.0"
+ strip-ansi "^6.0.1"
+
string.prototype.codepointat@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz#004ad44c8afc727527b108cd462b4d971cd469bc"
@@ -2807,6 +3178,13 @@ string.prototype.trimstart@^1.0.6:
define-properties "^1.1.4"
es-abstract "^1.20.4"
+string_decoder@^1.1.1:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
+ integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
+ dependencies:
+ safe-buffer "~5.2.0"
+
strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
@@ -2871,11 +3249,39 @@ tapable@^2.2.0:
resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==
+tar@^6.1.11:
+ version "6.2.0"
+ resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.0.tgz#b14ce49a79cb1cd23bc9b016302dea5474493f73"
+ integrity sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==
+ dependencies:
+ chownr "^2.0.0"
+ fs-minipass "^2.0.0"
+ minipass "^5.0.0"
+ minizlib "^2.1.1"
+ mkdirp "^1.0.3"
+ yallist "^4.0.0"
+
text-table@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
+three-forcegraph@^1.41.10:
+ version "1.41.10"
+ resolved "https://registry.yarnpkg.com/three-forcegraph/-/three-forcegraph-1.41.10.tgz#a162263b5c5db957c88cb496baff057f12bb26ef"
+ integrity sha512-XrrH0HzlWQiY5A30RMtlu+SpAM/LOoHMyaQouCFgavTSLrSsP4UIUP3eWrfJ0be1xDPuMGt3iofSYjgu4UT2NA==
+ dependencies:
+ accessor-fn "1"
+ d3-array "1 - 3"
+ d3-force-3d "2 - 3"
+ d3-scale "1 - 4"
+ d3-scale-chromatic "1 - 3"
+ data-joint "1"
+ kapsule "1"
+ ngraph.forcelayout "3"
+ ngraph.graph "20"
+ tinycolor2 "1"
+
three-mesh-bvh@^0.6.0:
version "0.6.1"
resolved "https://registry.yarnpkg.com/three-mesh-bvh/-/three-mesh-bvh-0.6.1.tgz#63cebe46ff90221286f97e1fea59b433bb95304f"
@@ -2908,6 +3314,21 @@ tiny-inflate@^1.0.3:
resolved "https://registry.yarnpkg.com/tiny-inflate/-/tiny-inflate-1.0.3.tgz#122715494913a1805166aaf7c93467933eea26c4"
integrity sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==
+tiny-invariant@^1.0.0:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.1.tgz#8560808c916ef02ecfd55e66090df23a4b7aa642"
+ integrity sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==
+
+tiny-warning@^1.0.0:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
+ integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
+
+tinycolor2@1:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.6.0.tgz#f98007460169b0263b97072c5ae92484ce02d09e"
+ integrity sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==
+
titleize@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/titleize/-/titleize-3.0.0.tgz#71c12eb7fdd2558aa8a44b0be83b8a76694acd53"
@@ -2920,6 +3341,11 @@ to-regex-range@^5.0.1:
dependencies:
is-number "^7.0.0"
+tr46@~0.0.3:
+ version "0.0.3"
+ resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
+ integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
+
troika-three-text@^0.47.2:
version "0.47.2"
resolved "https://registry.yarnpkg.com/troika-three-text/-/troika-three-text-0.47.2.tgz#fdf89059c010563bb829262b20c41f69ca79b712"
@@ -3036,6 +3462,11 @@ use-sync-external-store@1.2.0:
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"
integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==
+util-deprecate@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+ integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
+
utility-types@^3.10.0:
version "3.10.0"
resolved "https://registry.yarnpkg.com/utility-types/-/utility-types-3.10.0.tgz#ea4148f9a741015f05ed74fd615e1d20e6bed82b"
@@ -3059,6 +3490,19 @@ webgl-sdf-generator@1.1.1:
resolved "https://registry.yarnpkg.com/webgl-sdf-generator/-/webgl-sdf-generator-1.1.1.tgz#3e1b422b3d87cd3cc77f2602c9db63bc0f6accbd"
integrity sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==
+webidl-conversions@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
+ integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==
+
+whatwg-url@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
+ integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==
+ dependencies:
+ tr46 "~0.0.3"
+ webidl-conversions "^3.0.0"
+
which-boxed-primitive@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6"
@@ -3089,6 +3533,13 @@ which@^2.0.1:
dependencies:
isexe "^2.0.0"
+wide-align@^1.1.2:
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3"
+ integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==
+ dependencies:
+ string-width "^1.0.2 || 2 || 3 || 4"
+
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"