react-cheminfo 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/chrome/ui/NavLink.d.ts.map +1 -1
- package/lib/chrome/ui/NavLink.js +4 -3
- package/lib/chrome/ui/NavLink.js.map +1 -1
- package/lib/chrome/ui/SiteFooter.d.ts +8 -0
- package/lib/chrome/ui/SiteFooter.d.ts.map +1 -1
- package/lib/chrome/ui/SiteFooter.js +7 -2
- package/lib/chrome/ui/SiteFooter.js.map +1 -1
- package/lib/chrome/ui/SiteHeader.d.ts +11 -0
- package/lib/chrome/ui/SiteHeader.d.ts.map +1 -1
- package/lib/chrome/ui/SiteHeader.js +7 -2
- package/lib/chrome/ui/SiteHeader.js.map +1 -1
- package/lib/chrome/ui/navItem.d.ts +12 -0
- package/lib/chrome/ui/navItem.d.ts.map +1 -1
- package/lib/chrome/ui/navItem.js.map +1 -1
- package/lib/core.d.ts +1 -0
- package/lib/core.d.ts.map +1 -1
- package/lib/core.js +1 -0
- package/lib/core.js.map +1 -1
- package/lib/download/core/figureLegend.d.ts +90 -0
- package/lib/download/core/figureLegend.d.ts.map +1 -0
- package/lib/download/core/figureLegend.js +77 -0
- package/lib/download/core/figureLegend.js.map +1 -0
- package/lib/download/core/figureSvg.d.ts.map +1 -1
- package/lib/download/core/figureSvg.js +71 -1
- package/lib/download/core/figureSvg.js.map +1 -1
- package/lib/download/core/figureSvgDocument.d.ts +9 -2
- package/lib/download/core/figureSvgDocument.d.ts.map +1 -1
- package/lib/download/core/figureSvgDocument.js +4 -1
- package/lib/download/core/figureSvgDocument.js.map +1 -1
- package/lib/download/core/figureTarget.d.ts +11 -0
- package/lib/download/core/figureTarget.d.ts.map +1 -1
- package/lib/download/core/figureTarget.js +19 -0
- package/lib/download/core/figureTarget.js.map +1 -1
- package/lib/download/core/index.d.ts +3 -1
- package/lib/download/core/index.d.ts.map +1 -1
- package/lib/download/core/index.js +2 -1
- package/lib/download/core/index.js.map +1 -1
- package/lib/ecosystem/core/sites.d.ts +1 -1
- package/lib/ecosystem/core/sites.d.ts.map +1 -1
- package/lib/ecosystem/core/sites.js +13 -0
- package/lib/ecosystem/core/sites.js.map +1 -1
- package/lib/ecosystem/ui/glyphs.d.ts.map +1 -1
- package/lib/ecosystem/ui/glyphs.js +5 -0
- package/lib/ecosystem/ui/glyphs.js.map +1 -1
- package/lib/overlay/ui/OverlayLegend.d.ts.map +1 -1
- package/lib/overlay/ui/OverlayLegend.js +1 -1
- package/lib/overlay/ui/OverlayLegend.js.map +1 -1
- package/lib/projection/core/projectionCopy.d.ts +4 -0
- package/lib/projection/core/projectionCopy.d.ts.map +1 -1
- package/lib/projection/core/projectionCopy.js +3 -0
- package/lib/projection/core/projectionCopy.js.map +1 -1
- package/lib/projection/core/projectionOptions.d.ts +12 -0
- package/lib/projection/core/projectionOptions.d.ts.map +1 -1
- package/lib/projection/core/projectionOptions.js +27 -1
- package/lib/projection/core/projectionOptions.js.map +1 -1
- package/lib/projection/core/projectionStrings.d.ts +4 -0
- package/lib/projection/core/projectionStrings.d.ts.map +1 -1
- package/lib/projection/core/projectionStrings.js +14 -0
- package/lib/projection/core/projectionStrings.js.map +1 -1
- package/lib/projection/core/projectionTabDefaults.d.ts.map +1 -1
- package/lib/projection/core/projectionTabDefaults.js +12 -0
- package/lib/projection/core/projectionTabDefaults.js.map +1 -1
- package/lib/projection/core/projectionTabs.d.ts +1 -1
- package/lib/projection/core/projectionTabs.d.ts.map +1 -1
- package/lib/projection/core/projectionTabs.js +9 -0
- package/lib/projection/core/projectionTabs.js.map +1 -1
- package/lib/projection/ui/ProjectionMapTab.d.ts +6 -0
- package/lib/projection/ui/ProjectionMapTab.d.ts.map +1 -1
- package/lib/projection/ui/ProjectionMapTab.js +2 -1
- package/lib/projection/ui/ProjectionMapTab.js.map +1 -1
- package/lib/projection/ui/ProjectionPanel.d.ts +6 -0
- package/lib/projection/ui/ProjectionPanel.d.ts.map +1 -1
- package/lib/projection/ui/ProjectionPanel.js +15 -1
- package/lib/projection/ui/ProjectionPanel.js.map +1 -1
- package/lib/projection/ui/ProjectionReadout.d.ts +7 -0
- package/lib/projection/ui/ProjectionReadout.d.ts.map +1 -1
- package/lib/projection/ui/ProjectionReadout.js +5 -4
- package/lib/projection/ui/ProjectionReadout.js.map +1 -1
- package/lib/projection/ui/ProjectionSpaceControls.d.ts +51 -0
- package/lib/projection/ui/ProjectionSpaceControls.d.ts.map +1 -0
- package/lib/projection/ui/ProjectionSpaceControls.js +71 -0
- package/lib/projection/ui/ProjectionSpaceControls.js.map +1 -0
- package/lib/projection/ui/ProjectionSpaceMore.d.ts +32 -0
- package/lib/projection/ui/ProjectionSpaceMore.d.ts.map +1 -0
- package/lib/projection/ui/ProjectionSpaceMore.js +57 -0
- package/lib/projection/ui/ProjectionSpaceMore.js.map +1 -0
- package/lib/projection/ui/ProjectionSpaceTab.d.ts +98 -0
- package/lib/projection/ui/ProjectionSpaceTab.d.ts.map +1 -0
- package/lib/projection/ui/ProjectionSpaceTab.js +66 -0
- package/lib/projection/ui/ProjectionSpaceTab.js.map +1 -0
- package/lib/projection/ui/ProjectionViewer.d.ts +1 -0
- package/lib/projection/ui/ProjectionViewer.d.ts.map +1 -1
- package/lib/projection/ui/ProjectionViewer.js +2 -1
- package/lib/projection/ui/ProjectionViewer.js.map +1 -1
- package/lib/projection/ui/index.d.ts +1 -0
- package/lib/projection/ui/index.d.ts.map +1 -1
- package/lib/projection/ui/index.js.map +1 -1
- package/lib/projection/ui/projectionBarModel.d.ts.map +1 -1
- package/lib/projection/ui/projectionBarModel.js +3 -2
- package/lib/projection/ui/projectionBarModel.js.map +1 -1
- package/lib/projection/ui/projectionBarReadings.d.ts.map +1 -1
- package/lib/projection/ui/projectionBarReadings.js +17 -0
- package/lib/projection/ui/projectionBarReadings.js.map +1 -1
- package/lib/projection/ui/projectionBarSlots.d.ts.map +1 -1
- package/lib/projection/ui/projectionBarSlots.js +17 -0
- package/lib/projection/ui/projectionBarSlots.js.map +1 -1
- package/lib/projection/ui/projectionCloudChoices.d.ts +18 -0
- package/lib/projection/ui/projectionCloudChoices.d.ts.map +1 -0
- package/lib/projection/ui/projectionCloudChoices.js +19 -0
- package/lib/projection/ui/projectionCloudChoices.js.map +1 -0
- package/lib/projection/ui/projectionEllipsoid.d.ts +38 -0
- package/lib/projection/ui/projectionEllipsoid.d.ts.map +1 -0
- package/lib/projection/ui/projectionEllipsoid.js +71 -0
- package/lib/projection/ui/projectionEllipsoid.js.map +1 -0
- package/lib/projection/ui/projectionMapChrome.d.ts +8 -0
- package/lib/projection/ui/projectionMapChrome.d.ts.map +1 -1
- package/lib/projection/ui/projectionMapChrome.js +10 -6
- package/lib/projection/ui/projectionMapChrome.js.map +1 -1
- package/lib/projection/ui/projectionMapView.d.ts +13 -0
- package/lib/projection/ui/projectionMapView.d.ts.map +1 -1
- package/lib/projection/ui/projectionMapView.js +26 -0
- package/lib/projection/ui/projectionMapView.js.map +1 -1
- package/lib/projection/ui/projectionSpaceModel.d.ts +14 -0
- package/lib/projection/ui/projectionSpaceModel.d.ts.map +1 -0
- package/lib/projection/ui/projectionSpaceModel.js +14 -0
- package/lib/projection/ui/projectionSpaceModel.js.map +1 -0
- package/lib/projection/ui/projectionViewerProps.d.ts +34 -0
- package/lib/projection/ui/projectionViewerProps.d.ts.map +1 -1
- package/lib/scatter/ui/ScatterPlot.d.ts +1 -1
- package/lib/scatter/ui/ScatterPlot.d.ts.map +1 -1
- package/lib/scatter/ui/ScatterPlot.js +18 -2
- package/lib/scatter/ui/ScatterPlot.js.map +1 -1
- package/lib/scatter/ui/lassoGesture.d.ts +14 -2
- package/lib/scatter/ui/lassoGesture.d.ts.map +1 -1
- package/lib/scatter/ui/lassoGesture.js +4 -1
- package/lib/scatter/ui/lassoGesture.js.map +1 -1
- package/lib/scatter/ui/scatterPlotProps.d.ts +34 -0
- package/lib/scatter/ui/scatterPlotProps.d.ts.map +1 -1
- package/lib/scatter/ui/useScatterInteraction.d.ts +9 -0
- package/lib/scatter/ui/useScatterInteraction.d.ts.map +1 -1
- package/lib/scatter/ui/useScatterInteraction.js +9 -1
- package/lib/scatter/ui/useScatterInteraction.js.map +1 -1
- package/lib/scatter3d/core/cloudGesture.d.ts +17 -0
- package/lib/scatter3d/core/cloudGesture.d.ts.map +1 -0
- package/lib/scatter3d/core/cloudGesture.js +2 -0
- package/lib/scatter3d/core/cloudGesture.js.map +1 -0
- package/lib/scatter3d/core/confidenceEllipsoid.d.ts +63 -0
- package/lib/scatter3d/core/confidenceEllipsoid.d.ts.map +1 -0
- package/lib/scatter3d/core/confidenceEllipsoid.js +128 -0
- package/lib/scatter3d/core/confidenceEllipsoid.js.map +1 -0
- package/lib/scatter3d/core/cubeFrame.d.ts +40 -0
- package/lib/scatter3d/core/cubeFrame.d.ts.map +1 -0
- package/lib/scatter3d/core/cubeFrame.js +58 -0
- package/lib/scatter3d/core/cubeFrame.js.map +1 -0
- package/lib/scatter3d/core/cubePoints.d.ts +35 -0
- package/lib/scatter3d/core/cubePoints.d.ts.map +1 -0
- package/lib/scatter3d/core/cubePoints.js +50 -0
- package/lib/scatter3d/core/cubePoints.js.map +1 -0
- package/lib/scatter3d/core/ellipsoidCoverage.d.ts +32 -0
- package/lib/scatter3d/core/ellipsoidCoverage.d.ts.map +1 -0
- package/lib/scatter3d/core/ellipsoidCoverage.js +83 -0
- package/lib/scatter3d/core/ellipsoidCoverage.js.map +1 -0
- package/lib/scatter3d/core/ellipsoidSilhouette.d.ts +42 -0
- package/lib/scatter3d/core/ellipsoidSilhouette.d.ts.map +1 -0
- package/lib/scatter3d/core/ellipsoidSilhouette.js +52 -0
- package/lib/scatter3d/core/ellipsoidSilhouette.js.map +1 -0
- package/lib/scatter3d/core/index.d.ts +29 -0
- package/lib/scatter3d/core/index.d.ts.map +1 -0
- package/lib/scatter3d/core/index.js +22 -0
- package/lib/scatter3d/core/index.js.map +1 -0
- package/lib/scatter3d/core/orbitCamera.d.ts +113 -0
- package/lib/scatter3d/core/orbitCamera.d.ts.map +1 -0
- package/lib/scatter3d/core/orbitCamera.js +104 -0
- package/lib/scatter3d/core/orbitCamera.js.map +1 -0
- package/lib/scatter3d/core/symmetricEigen.d.ts +47 -0
- package/lib/scatter3d/core/symmetricEigen.d.ts.map +1 -0
- package/lib/scatter3d/core/symmetricEigen.js +219 -0
- package/lib/scatter3d/core/symmetricEigen.js.map +1 -0
- package/lib/scatter3d/ui/CloudFrameLayer.d.ts +33 -0
- package/lib/scatter3d/ui/CloudFrameLayer.d.ts.map +1 -0
- package/lib/scatter3d/ui/CloudFrameLayer.js +37 -0
- package/lib/scatter3d/ui/CloudFrameLayer.js.map +1 -0
- package/lib/scatter3d/ui/CloudPointLayer.d.ts +62 -0
- package/lib/scatter3d/ui/CloudPointLayer.d.ts.map +1 -0
- package/lib/scatter3d/ui/CloudPointLayer.js +67 -0
- package/lib/scatter3d/ui/CloudPointLayer.js.map +1 -0
- package/lib/scatter3d/ui/CloudShellLayer.d.ts +52 -0
- package/lib/scatter3d/ui/CloudShellLayer.d.ts.map +1 -0
- package/lib/scatter3d/ui/CloudShellLayer.js +40 -0
- package/lib/scatter3d/ui/CloudShellLayer.js.map +1 -0
- package/lib/scatter3d/ui/ScatterCloud.d.ts +24 -0
- package/lib/scatter3d/ui/ScatterCloud.d.ts.map +1 -0
- package/lib/scatter3d/ui/ScatterCloud.js +189 -0
- package/lib/scatter3d/ui/ScatterCloud.js.map +1 -0
- package/lib/scatter3d/ui/cloudGeometry.d.ts +108 -0
- package/lib/scatter3d/ui/cloudGeometry.d.ts.map +1 -0
- package/lib/scatter3d/ui/cloudGeometry.js +122 -0
- package/lib/scatter3d/ui/cloudGeometry.js.map +1 -0
- package/lib/scatter3d/ui/cloudShellStyles.d.ts +36 -0
- package/lib/scatter3d/ui/cloudShellStyles.d.ts.map +1 -0
- package/lib/scatter3d/ui/cloudShellStyles.js +62 -0
- package/lib/scatter3d/ui/cloudShellStyles.js.map +1 -0
- package/lib/scatter3d/ui/cloudZoom.d.ts +21 -0
- package/lib/scatter3d/ui/cloudZoom.d.ts.map +1 -0
- package/lib/scatter3d/ui/cloudZoom.js +22 -0
- package/lib/scatter3d/ui/cloudZoom.js.map +1 -0
- package/lib/scatter3d/ui/index.d.ts +29 -0
- package/lib/scatter3d/ui/index.d.ts.map +1 -0
- package/lib/scatter3d/ui/index.js +21 -0
- package/lib/scatter3d/ui/index.js.map +1 -0
- package/lib/scatter3d/ui/scatterCloudModel.d.ts +60 -0
- package/lib/scatter3d/ui/scatterCloudModel.d.ts.map +1 -0
- package/lib/scatter3d/ui/scatterCloudModel.js +66 -0
- package/lib/scatter3d/ui/scatterCloudModel.js.map +1 -0
- package/lib/scatter3d/ui/scatterCloudProps.d.ts +185 -0
- package/lib/scatter3d/ui/scatterCloudProps.d.ts.map +1 -0
- package/lib/scatter3d/ui/scatterCloudProps.js +9 -0
- package/lib/scatter3d/ui/scatterCloudProps.js.map +1 -0
- package/lib/scatter3d/ui/useOrbitDrag.d.ts +60 -0
- package/lib/scatter3d/ui/useOrbitDrag.d.ts.map +1 -0
- package/lib/scatter3d/ui/useOrbitDrag.js +129 -0
- package/lib/scatter3d/ui/useOrbitDrag.js.map +1 -0
- package/lib/ui.d.ts +1 -0
- package/lib/ui.d.ts.map +1 -1
- package/lib/ui.js +1 -0
- package/lib/ui.js.map +1 -1
- package/package.json +1 -1
- package/src/chrome/ui/NavLink.tsx +5 -3
- package/src/chrome/ui/SiteFooter.tsx +16 -1
- package/src/chrome/ui/SiteHeader.tsx +19 -1
- package/src/chrome/ui/navItem.ts +12 -0
- package/src/core.ts +1 -0
- package/src/download/core/figureLegend.ts +167 -0
- package/src/download/core/figureSvg.ts +81 -1
- package/src/download/core/figureSvgDocument.ts +13 -3
- package/src/download/core/figureTarget.ts +21 -0
- package/src/download/core/index.ts +8 -0
- package/src/ecosystem/core/sites.ts +14 -0
- package/src/ecosystem/ui/glyphs.tsx +26 -0
- package/src/overlay/ui/OverlayLegend.tsx +7 -1
- package/src/projection/core/projectionCopy.ts +9 -0
- package/src/projection/core/projectionOptions.ts +48 -3
- package/src/projection/core/projectionStrings.ts +16 -0
- package/src/projection/core/projectionTabDefaults.ts +12 -0
- package/src/projection/core/projectionTabs.ts +10 -1
- package/src/projection/ui/ProjectionMapTab.tsx +8 -0
- package/src/projection/ui/ProjectionPanel.tsx +63 -0
- package/src/projection/ui/ProjectionReadout.tsx +16 -6
- package/src/projection/ui/ProjectionSpaceControls.tsx +219 -0
- package/src/projection/ui/ProjectionSpaceMore.tsx +169 -0
- package/src/projection/ui/ProjectionSpaceTab.tsx +217 -0
- package/src/projection/ui/ProjectionViewer.tsx +3 -0
- package/src/projection/ui/index.ts +1 -0
- package/src/projection/ui/projectionBarModel.ts +3 -2
- package/src/projection/ui/projectionBarReadings.ts +18 -0
- package/src/projection/ui/projectionBarSlots.tsx +19 -0
- package/src/projection/ui/projectionCloudChoices.ts +23 -0
- package/src/projection/ui/projectionEllipsoid.ts +78 -0
- package/src/projection/ui/projectionMapChrome.ts +26 -5
- package/src/projection/ui/projectionMapView.ts +45 -0
- package/src/projection/ui/projectionSpaceModel.ts +14 -0
- package/src/projection/ui/projectionViewerProps.ts +35 -0
- package/src/scatter/ui/ScatterPlot.tsx +21 -2
- package/src/scatter/ui/lassoGesture.ts +15 -2
- package/src/scatter/ui/scatterPlotProps.ts +35 -0
- package/src/scatter/ui/useScatterInteraction.ts +22 -1
- package/src/scatter3d/core/cloudGesture.ts +16 -0
- package/src/scatter3d/core/confidenceEllipsoid.ts +177 -0
- package/src/scatter3d/core/cubeFrame.ts +72 -0
- package/src/scatter3d/core/cubePoints.ts +75 -0
- package/src/scatter3d/core/ellipsoidCoverage.ts +86 -0
- package/src/scatter3d/core/ellipsoidSilhouette.ts +76 -0
- package/src/scatter3d/core/index.ts +52 -0
- package/src/scatter3d/core/orbitCamera.ts +159 -0
- package/src/scatter3d/core/symmetricEigen.ts +273 -0
- package/src/scatter3d/ui/CloudFrameLayer.tsx +97 -0
- package/src/scatter3d/ui/CloudPointLayer.tsx +132 -0
- package/src/scatter3d/ui/CloudShellLayer.tsx +107 -0
- package/src/scatter3d/ui/ScatterCloud.tsx +312 -0
- package/src/scatter3d/ui/cloudGeometry.ts +200 -0
- package/src/scatter3d/ui/cloudShellStyles.ts +74 -0
- package/src/scatter3d/ui/cloudZoom.ts +22 -0
- package/src/scatter3d/ui/index.ts +41 -0
- package/src/scatter3d/ui/scatterCloudModel.ts +98 -0
- package/src/scatter3d/ui/scatterCloudProps.ts +191 -0
- package/src/scatter3d/ui/useOrbitDrag.ts +220 -0
- package/src/ui.ts +1 -0
- package/styles/chrome.css +29 -4
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { useCallback, useMemo, useRef, useState } from 'react';
|
|
2
|
+
import { capturePointer, dropFrame, modifierMode, scheduleFrame, surfacePosition, } from "../../scatter/ui/lassoGesture.js";
|
|
3
|
+
import { orbitByDrag } from "../core/orbitCamera.js";
|
|
4
|
+
/**
|
|
5
|
+
* Turning the box with the pointer.
|
|
6
|
+
*
|
|
7
|
+
* It is the lasso's twin and is built the same way — the pointer is captured
|
|
8
|
+
* on the way down so a drag that wanders off the figure keeps turning it, all
|
|
9
|
+
* three ways a capture can end lead to one function, and moves are coalesced
|
|
10
|
+
* to one a frame because a pointer emits many per frame and each one that
|
|
11
|
+
* reaches the caller repaints every dot and every face.
|
|
12
|
+
*
|
|
13
|
+
* A press that goes nowhere is a tap rather than a turn of no degrees, because
|
|
14
|
+
* nobody presses a mouse button without moving it a pixel or two and a reader
|
|
15
|
+
* who meant to pick a sample must not have to hold their hand still to do it.
|
|
16
|
+
* @param options - See {@link OrbitDragOptions}.
|
|
17
|
+
* @returns The drag. See {@link OrbitDrag}.
|
|
18
|
+
*/
|
|
19
|
+
export function useOrbitDrag(options) {
|
|
20
|
+
const { enabled = true, onOrbit, onTap, onMove, onLeave, mode: restingMode = 'replace', } = options;
|
|
21
|
+
const pointerRef = useRef(null);
|
|
22
|
+
const lastRef = useRef({ x: 0, y: 0 });
|
|
23
|
+
const travelRef = useRef(0);
|
|
24
|
+
const frameRef = useRef(null);
|
|
25
|
+
const pendingRef = useRef(null);
|
|
26
|
+
const [turning, setTurning] = useState(false);
|
|
27
|
+
const flush = useCallback(() => {
|
|
28
|
+
frameRef.current = null;
|
|
29
|
+
const next = pendingRef.current;
|
|
30
|
+
pendingRef.current = null;
|
|
31
|
+
if (next === null)
|
|
32
|
+
return;
|
|
33
|
+
if (pointerRef.current === null) {
|
|
34
|
+
onMove?.(next.x, next.y);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
onOrbit((camera) => orbitByDrag(camera, next.dx, next.dy));
|
|
38
|
+
}, [onMove, onOrbit]);
|
|
39
|
+
const end = useCallback((event, commit) => {
|
|
40
|
+
if (event.pointerId !== pointerRef.current)
|
|
41
|
+
return;
|
|
42
|
+
pointerRef.current = null;
|
|
43
|
+
pendingRef.current = null;
|
|
44
|
+
dropFrame(frameRef);
|
|
45
|
+
setTurning(false);
|
|
46
|
+
if (!commit || travelRef.current > TAP_SLACK)
|
|
47
|
+
return;
|
|
48
|
+
const at = surfacePosition(event, 0, 0);
|
|
49
|
+
onTap?.(at.x, at.y, modifierMode(event, restingMode));
|
|
50
|
+
}, [onTap, restingMode]);
|
|
51
|
+
const handleDown = useCallback((event) => {
|
|
52
|
+
if (pointerRef.current !== null || event.button > 0)
|
|
53
|
+
return;
|
|
54
|
+
pointerRef.current = event.pointerId;
|
|
55
|
+
lastRef.current = { x: event.clientX, y: event.clientY };
|
|
56
|
+
travelRef.current = 0;
|
|
57
|
+
setTurning(true);
|
|
58
|
+
capturePointer(event);
|
|
59
|
+
}, []);
|
|
60
|
+
const handleMove = useCallback((event) => {
|
|
61
|
+
const active = pointerRef.current;
|
|
62
|
+
if (active === null) {
|
|
63
|
+
const at = surfacePosition(event, 0, 0);
|
|
64
|
+
pendingRef.current = { x: at.x, y: at.y, dx: 0, dy: 0 };
|
|
65
|
+
scheduleFrame(frameRef, flush);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (event.pointerId !== active)
|
|
69
|
+
return;
|
|
70
|
+
const last = lastRef.current;
|
|
71
|
+
const dx = event.clientX - last.x;
|
|
72
|
+
const dy = event.clientY - last.y;
|
|
73
|
+
lastRef.current = { x: event.clientX, y: event.clientY };
|
|
74
|
+
travelRef.current += Math.abs(dx) + Math.abs(dy);
|
|
75
|
+
if (!enabled)
|
|
76
|
+
return;
|
|
77
|
+
const waiting = pendingRef.current;
|
|
78
|
+
pendingRef.current = {
|
|
79
|
+
x: 0,
|
|
80
|
+
y: 0,
|
|
81
|
+
dx: (waiting?.dx ?? 0) + dx,
|
|
82
|
+
dy: (waiting?.dy ?? 0) + dy,
|
|
83
|
+
};
|
|
84
|
+
scheduleFrame(frameRef, flush);
|
|
85
|
+
}, [enabled, flush]);
|
|
86
|
+
const handleUp = useCallback((event) => {
|
|
87
|
+
end(event, true);
|
|
88
|
+
}, [end]);
|
|
89
|
+
const handleAbandon = useCallback((event) => {
|
|
90
|
+
end(event, false);
|
|
91
|
+
}, [end]);
|
|
92
|
+
const handleLeave = useCallback(() => {
|
|
93
|
+
if (pointerRef.current !== null)
|
|
94
|
+
return;
|
|
95
|
+
pendingRef.current = null;
|
|
96
|
+
onLeave?.();
|
|
97
|
+
}, [onLeave]);
|
|
98
|
+
const surface = useMemo(() => ({
|
|
99
|
+
onPointerDown: handleDown,
|
|
100
|
+
onPointerMove: handleMove,
|
|
101
|
+
onPointerUp: handleUp,
|
|
102
|
+
onPointerCancel: handleAbandon,
|
|
103
|
+
onLostPointerCapture: handleAbandon,
|
|
104
|
+
onPointerLeave: handleLeave,
|
|
105
|
+
style: {
|
|
106
|
+
cursor: enabled ? (turning ? 'grabbing' : 'grab') : 'default',
|
|
107
|
+
touchAction: 'none',
|
|
108
|
+
},
|
|
109
|
+
}), [
|
|
110
|
+
enabled,
|
|
111
|
+
handleAbandon,
|
|
112
|
+
handleDown,
|
|
113
|
+
handleLeave,
|
|
114
|
+
handleMove,
|
|
115
|
+
handleUp,
|
|
116
|
+
turning,
|
|
117
|
+
]);
|
|
118
|
+
return { turning, surface };
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* How far a press may travel and still be a tap, in pixels of total travel.
|
|
122
|
+
*
|
|
123
|
+
* Generous on purpose: a mouse moves a pixel or two under the click of its own
|
|
124
|
+
* button, and a finger moves rather more, so a stricter number turns "pick
|
|
125
|
+
* this sample" into "turn the box by nothing at all" for anybody whose hand is
|
|
126
|
+
* not steady.
|
|
127
|
+
*/
|
|
128
|
+
const TAP_SLACK = 5;
|
|
129
|
+
//# sourceMappingURL=useOrbitDrag.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useOrbitDrag.js","sourceRoot":"","sources":["../../../src/scatter3d/ui/useOrbitDrag.ts"],"names":[],"mappings":"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"}
|
package/lib/ui.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ export * from './pedagogy/ui/index.ts';
|
|
|
18
18
|
export * from './periodic/ui/index.ts';
|
|
19
19
|
export * from './projection/ui/index.ts';
|
|
20
20
|
export * from './scatter/ui/index.ts';
|
|
21
|
+
export * from './scatter3d/ui/index.ts';
|
|
21
22
|
export * from './share/ui/index.ts';
|
|
22
23
|
export * from './shared/ui/index.ts';
|
|
23
24
|
export * from './spectra/ui/index.ts';
|
package/lib/ui.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC"}
|
package/lib/ui.js
CHANGED
|
@@ -18,6 +18,7 @@ export * from "./pedagogy/ui/index.js";
|
|
|
18
18
|
export * from "./periodic/ui/index.js";
|
|
19
19
|
export * from "./projection/ui/index.js";
|
|
20
20
|
export * from "./scatter/ui/index.js";
|
|
21
|
+
export * from "./scatter3d/ui/index.js";
|
|
21
22
|
export * from "./share/ui/index.js";
|
|
22
23
|
export * from "./shared/ui/index.js";
|
|
23
24
|
export * from "./spectra/ui/index.js";
|
package/lib/ui.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC"}
|
package/package.json
CHANGED
|
@@ -30,24 +30,26 @@ export interface NavLinkProps {
|
|
|
30
30
|
*/
|
|
31
31
|
export function NavLink(props: NavLinkProps): ReactElement {
|
|
32
32
|
const { item, active = false, className } = props;
|
|
33
|
-
const { href, external = false, onSelect, title } = item;
|
|
33
|
+
const { href, external = false, onSelect, title, disabled = false } = item;
|
|
34
34
|
|
|
35
35
|
const classes = [
|
|
36
36
|
'nav-link',
|
|
37
37
|
active ? 'nav-link--active' : null,
|
|
38
|
+
disabled ? 'nav-link--disabled' : null,
|
|
38
39
|
className ?? null,
|
|
39
40
|
]
|
|
40
41
|
.filter((part) => part !== null)
|
|
41
42
|
.join(' ');
|
|
42
43
|
|
|
43
|
-
if (href === undefined) {
|
|
44
|
+
if (href === undefined || disabled) {
|
|
44
45
|
return (
|
|
45
46
|
<button
|
|
46
47
|
type="button"
|
|
47
48
|
className={classes}
|
|
48
49
|
title={title}
|
|
49
50
|
aria-label={title}
|
|
50
|
-
|
|
51
|
+
disabled={disabled}
|
|
52
|
+
onClick={disabled ? undefined : onSelect}
|
|
51
53
|
>
|
|
52
54
|
<NavLinkBody item={item} />
|
|
53
55
|
</button>
|
|
@@ -29,6 +29,14 @@ export interface SiteFooterProps {
|
|
|
29
29
|
* @default undefined
|
|
30
30
|
*/
|
|
31
31
|
children?: ReactNode;
|
|
32
|
+
/**
|
|
33
|
+
* How wide the footer's contents run, read exactly as `SiteHeader`'s: `page`
|
|
34
|
+
* caps them at `--page-max`, `full` runs them to both edges. A site sets the
|
|
35
|
+
* two alike, or its chrome is capped at one end of the page and not at the
|
|
36
|
+
* other.
|
|
37
|
+
* @default 'page'
|
|
38
|
+
*/
|
|
39
|
+
width?: 'page' | 'full';
|
|
32
40
|
}
|
|
33
41
|
|
|
34
42
|
/**
|
|
@@ -46,13 +54,14 @@ export function SiteFooter(props: SiteFooterProps): ReactElement | null {
|
|
|
46
54
|
heading,
|
|
47
55
|
embedded = false,
|
|
48
56
|
children,
|
|
57
|
+
width = 'page',
|
|
49
58
|
} = props;
|
|
50
59
|
|
|
51
60
|
if (embedded) return null;
|
|
52
61
|
|
|
53
62
|
return (
|
|
54
63
|
<footer className="app-footer no-print">
|
|
55
|
-
<div className=
|
|
64
|
+
<div className={INNER_CLASS[width]}>
|
|
56
65
|
<EcosystemLinks
|
|
57
66
|
currentSiteId={siteId}
|
|
58
67
|
layout={layout}
|
|
@@ -63,3 +72,9 @@ export function SiteFooter(props: SiteFooterProps): ReactElement | null {
|
|
|
63
72
|
</footer>
|
|
64
73
|
);
|
|
65
74
|
}
|
|
75
|
+
|
|
76
|
+
/** The two widths the footer's contents run at, as the classes that set them. */
|
|
77
|
+
const INNER_CLASS = {
|
|
78
|
+
page: 'app-footer__inner',
|
|
79
|
+
full: 'app-footer__inner app-footer__inner--full',
|
|
80
|
+
} as const;
|
|
@@ -55,6 +55,17 @@ export interface SiteHeaderProps {
|
|
|
55
55
|
* @default 28
|
|
56
56
|
*/
|
|
57
57
|
markSize?: number;
|
|
58
|
+
/**
|
|
59
|
+
* How wide the bar's contents run.
|
|
60
|
+
*
|
|
61
|
+
* `page` caps them at `--page-max` and centres them, so the brand sits over
|
|
62
|
+
* the first word of a page that is capped the same way — which is what a
|
|
63
|
+
* site of reading matter wants. `full` runs them to both edges, for a tool
|
|
64
|
+
* that fills the window: there the cap leaves the brand floating inwards
|
|
65
|
+
* with the tool running past it on both sides, and reads as a fault.
|
|
66
|
+
* @default 'page'
|
|
67
|
+
*/
|
|
68
|
+
width?: 'page' | 'full';
|
|
58
69
|
}
|
|
59
70
|
|
|
60
71
|
/**
|
|
@@ -76,6 +87,7 @@ export function SiteHeader(props: SiteHeaderProps): ReactElement | null {
|
|
|
76
87
|
homeHref = '/',
|
|
77
88
|
onHome,
|
|
78
89
|
markSize = 28,
|
|
90
|
+
width = 'page',
|
|
79
91
|
} = props;
|
|
80
92
|
|
|
81
93
|
if (embedded) return null;
|
|
@@ -84,7 +96,7 @@ export function SiteHeader(props: SiteHeaderProps): ReactElement | null {
|
|
|
84
96
|
|
|
85
97
|
return (
|
|
86
98
|
<header className="app-header no-print">
|
|
87
|
-
<div className=
|
|
99
|
+
<div className={INNER_CLASS[width]}>
|
|
88
100
|
<a
|
|
89
101
|
className="brand"
|
|
90
102
|
href={homeHref}
|
|
@@ -117,3 +129,9 @@ export function SiteHeader(props: SiteHeaderProps): ReactElement | null {
|
|
|
117
129
|
</header>
|
|
118
130
|
);
|
|
119
131
|
}
|
|
132
|
+
|
|
133
|
+
/** The two widths the bar's contents run at, as the classes that set them. */
|
|
134
|
+
const INNER_CLASS = {
|
|
135
|
+
page: 'app-header__inner',
|
|
136
|
+
full: 'app-header__inner app-header__inner--full',
|
|
137
|
+
} as const;
|
package/src/chrome/ui/navItem.ts
CHANGED
|
@@ -47,6 +47,18 @@ export interface NavItem {
|
|
|
47
47
|
* @default undefined
|
|
48
48
|
*/
|
|
49
49
|
after?: ReactNode;
|
|
50
|
+
/**
|
|
51
|
+
* Whether the page cannot be opened yet — a view that needs data the site
|
|
52
|
+
* has not been given.
|
|
53
|
+
*
|
|
54
|
+
* It is greyed rather than left out, because a bar that grows entries as a
|
|
55
|
+
* reader works is a bar they have to keep re-reading, and a page they cannot
|
|
56
|
+
* see is a page they conclude the site does not have. `title` is where the
|
|
57
|
+
* reason goes; without one the entry is dead and says nothing, which is the
|
|
58
|
+
* one thing worse than leaving it out.
|
|
59
|
+
* @default false
|
|
60
|
+
*/
|
|
61
|
+
disabled?: boolean;
|
|
50
62
|
}
|
|
51
63
|
|
|
52
64
|
/**
|
package/src/core.ts
CHANGED
|
@@ -15,6 +15,7 @@ export * from './periodic/core/index.ts';
|
|
|
15
15
|
export * from './projection/core/index.ts';
|
|
16
16
|
export * from './router/core/index.ts';
|
|
17
17
|
export * from './scatter/core/index.ts';
|
|
18
|
+
export * from './scatter3d/core/index.ts';
|
|
18
19
|
export * from './seo/core/index.ts';
|
|
19
20
|
export * from './share/core/index.ts';
|
|
20
21
|
// The deck format and its navigation are framework-free, so a backend can read
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The key, painted into the file the figure leaves the page as.
|
|
3
|
+
*
|
|
4
|
+
* A legend is HTML — it is a filter the reader presses, not a drawing — so it
|
|
5
|
+
* is inside the chrome the export otherwise leaves behind. But a saved figure
|
|
6
|
+
* without its key says nothing: a reader looking at three colours has no way
|
|
7
|
+
* back to the three species. So the card is redrawn, once, in SVG, from the
|
|
8
|
+
* boxes the browser laid it out in.
|
|
9
|
+
*
|
|
10
|
+
* It is redrawn from measurements rather than re-derived from the styles that
|
|
11
|
+
* made it, so the copy cannot drift from the card on screen: whatever the
|
|
12
|
+
* browser did with the wrapping, the folding and the type, that is what the
|
|
13
|
+
* file gets.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** The card the entries sit on. */
|
|
17
|
+
export interface FigureLegendCard {
|
|
18
|
+
/** Its width, in pixels. */
|
|
19
|
+
width: number;
|
|
20
|
+
/** Its height. */
|
|
21
|
+
height: number;
|
|
22
|
+
/**
|
|
23
|
+
* How round its corners are, in pixels.
|
|
24
|
+
* @default 0
|
|
25
|
+
*/
|
|
26
|
+
radius?: number;
|
|
27
|
+
/**
|
|
28
|
+
* What is painted behind it.
|
|
29
|
+
* @default undefined — nothing is painted
|
|
30
|
+
*/
|
|
31
|
+
background?: string;
|
|
32
|
+
/**
|
|
33
|
+
* The colour of the line round it.
|
|
34
|
+
* @default undefined — no line is drawn
|
|
35
|
+
*/
|
|
36
|
+
border?: string;
|
|
37
|
+
/**
|
|
38
|
+
* How heavy that line is, in pixels.
|
|
39
|
+
* @default 1
|
|
40
|
+
*/
|
|
41
|
+
borderWidth?: number;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** One mark of the key, already an SVG of its own. */
|
|
45
|
+
export interface FigureLegendMark {
|
|
46
|
+
/** The `<svg>` element as it was serialized, tokens already resolved. */
|
|
47
|
+
markup: string;
|
|
48
|
+
/** Its left edge, in pixels from the left of the card. */
|
|
49
|
+
x: number;
|
|
50
|
+
/** Its top edge, in pixels from the top of the card. */
|
|
51
|
+
y: number;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** One run of words of the key. */
|
|
55
|
+
export interface FigureLegendText {
|
|
56
|
+
/** What it says. */
|
|
57
|
+
text: string;
|
|
58
|
+
/** Its left edge, in pixels from the left of the card. */
|
|
59
|
+
x: number;
|
|
60
|
+
/** The middle of its line, in pixels from the top of the card. */
|
|
61
|
+
y: number;
|
|
62
|
+
/**
|
|
63
|
+
* Its colour.
|
|
64
|
+
* @default undefined — the document's own
|
|
65
|
+
*/
|
|
66
|
+
color?: string;
|
|
67
|
+
/**
|
|
68
|
+
* Its size, in pixels.
|
|
69
|
+
* @default undefined — the document's own
|
|
70
|
+
*/
|
|
71
|
+
fontSize?: number;
|
|
72
|
+
/**
|
|
73
|
+
* Its weight.
|
|
74
|
+
* @default undefined — the document's own
|
|
75
|
+
*/
|
|
76
|
+
fontWeight?: string;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** A key, measured off the page and ready to be painted. */
|
|
80
|
+
export interface FigureLegendPrint {
|
|
81
|
+
/** The card itself. */
|
|
82
|
+
card: FigureLegendCard;
|
|
83
|
+
/** Its marks, in the order they are drawn. */
|
|
84
|
+
marks: readonly FigureLegendMark[];
|
|
85
|
+
/** Its words, in the order they are drawn. */
|
|
86
|
+
texts: readonly FigureLegendText[];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* A key, as the markup that goes into the saved figure.
|
|
91
|
+
* @param print - The card, its marks and its words. See {@link FigureLegendPrint}.
|
|
92
|
+
* @returns The markup, in the card's own coordinates: the caller places it.
|
|
93
|
+
*/
|
|
94
|
+
export function figureLegendMarkup(print: FigureLegendPrint): string {
|
|
95
|
+
const { card, marks, texts } = print;
|
|
96
|
+
const parts: string[] = [groundMarkup(card)];
|
|
97
|
+
|
|
98
|
+
for (const mark of marks) {
|
|
99
|
+
parts.push(
|
|
100
|
+
`<g transform="translate(${round(mark.x)} ${round(mark.y)})">${mark.markup}</g>`,
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
for (const run of texts) parts.push(textMarkup(run));
|
|
104
|
+
|
|
105
|
+
return parts.join('');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The card the entries are written on.
|
|
110
|
+
* @param card - Its measurements. See {@link FigureLegendCard}.
|
|
111
|
+
* @returns Its markup, or nothing when the card has neither ground nor line.
|
|
112
|
+
*/
|
|
113
|
+
function groundMarkup(card: FigureLegendCard): string {
|
|
114
|
+
const { width, height, radius = 0, background, border } = card;
|
|
115
|
+
if (background === undefined && border === undefined) return '';
|
|
116
|
+
|
|
117
|
+
const borderWidth = card.borderWidth ?? 1;
|
|
118
|
+
// Drawn inside its own line, which a stroke otherwise straddles: half of it
|
|
119
|
+
// would fall outside the card and be clipped by the figure's edge.
|
|
120
|
+
const inset = border === undefined ? 0 : borderWidth / 2;
|
|
121
|
+
const line =
|
|
122
|
+
border === undefined
|
|
123
|
+
? ''
|
|
124
|
+
: ` stroke="${attribute(border)}" stroke-width="${round(borderWidth)}"`;
|
|
125
|
+
|
|
126
|
+
return (
|
|
127
|
+
`<rect x="${round(inset)}" y="${round(inset)}"` +
|
|
128
|
+
` width="${round(Math.max(0, width - inset * 2))}"` +
|
|
129
|
+
` height="${round(Math.max(0, height - inset * 2))}"` +
|
|
130
|
+
` rx="${round(radius)}" fill="${attribute(background ?? 'none')}"${line}/>`
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* One run of words, set on the middle of the line it was laid out on.
|
|
136
|
+
* @param run - The words and where they sit. See {@link FigureLegendText}.
|
|
137
|
+
* @returns Its markup, or nothing when it says nothing.
|
|
138
|
+
*/
|
|
139
|
+
function textMarkup(run: FigureLegendText): string {
|
|
140
|
+
if (run.text === '') return '';
|
|
141
|
+
|
|
142
|
+
const fill = run.color === undefined ? '' : ` fill="${attribute(run.color)}"`;
|
|
143
|
+
const size =
|
|
144
|
+
run.fontSize === undefined ? '' : ` font-size="${round(run.fontSize)}px"`;
|
|
145
|
+
const weight =
|
|
146
|
+
run.fontWeight === undefined
|
|
147
|
+
? ''
|
|
148
|
+
: ` font-weight="${attribute(run.fontWeight)}"`;
|
|
149
|
+
|
|
150
|
+
return (
|
|
151
|
+
`<text x="${round(run.x)}" y="${round(run.y)}" dominant-baseline="central"` +
|
|
152
|
+
`${fill}${size}${weight}>${text(run.text)}</text>`
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function attribute(value: string): string {
|
|
157
|
+
return text(value).replaceAll('"', '"');
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function text(value: string): string {
|
|
161
|
+
return value
|
|
162
|
+
.replaceAll('&', '&')
|
|
163
|
+
.replaceAll('<', '<')
|
|
164
|
+
.replaceAll('>', '>');
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const round = (value: number): number => Math.round(value * 100) / 100;
|
|
@@ -8,9 +8,16 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { cssTokenNames, resolveCssTokens } from './cssTokens.ts';
|
|
11
|
+
import type { FigureLegendMark, FigureLegendText } from './figureLegend.ts';
|
|
12
|
+
import { figureLegendMarkup } from './figureLegend.ts';
|
|
11
13
|
import type { FigurePiece } from './figureSvgDocument.ts';
|
|
12
14
|
import { figureSvgDocument } from './figureSvgDocument.ts';
|
|
13
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
figureBounds,
|
|
17
|
+
figureDrawings,
|
|
18
|
+
figureElement,
|
|
19
|
+
figureLegends,
|
|
20
|
+
} from './figureTarget.ts';
|
|
14
21
|
|
|
15
22
|
/** How the figure is copied. */
|
|
16
23
|
export interface FigureSvgOptions {
|
|
@@ -69,6 +76,17 @@ export function figureSvg(
|
|
|
69
76
|
});
|
|
70
77
|
}
|
|
71
78
|
|
|
79
|
+
for (const legend of figureLegends(element)) {
|
|
80
|
+
const box = legend.getBoundingClientRect();
|
|
81
|
+
if (box.width <= 0 || box.height <= 0) continue;
|
|
82
|
+
pieces.push({
|
|
83
|
+
markup: legendMarkup(legend, box),
|
|
84
|
+
x: box.left - bounds.left,
|
|
85
|
+
y: box.top - bounds.top,
|
|
86
|
+
kind: 'legend',
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
72
90
|
const styles = window.getComputedStyle(element);
|
|
73
91
|
const markup = figureSvgDocument(pieces, {
|
|
74
92
|
width: bounds.width,
|
|
@@ -85,6 +103,68 @@ export function figureSvg(
|
|
|
85
103
|
};
|
|
86
104
|
}
|
|
87
105
|
|
|
106
|
+
/**
|
|
107
|
+
* One key, measured off the page and painted as SVG.
|
|
108
|
+
*
|
|
109
|
+
* Everything is read from where the browser put it — the card's own ground and
|
|
110
|
+
* corner, each mark's box, each run of words and the type it is set in — so
|
|
111
|
+
* the copy in the file is the card the reader was looking at, folding and all.
|
|
112
|
+
* The ground is painted at full strength however faint the card had gone on
|
|
113
|
+
* screen: a key that fades when the pointer leaves the figure is a property of
|
|
114
|
+
* pointing at it, not of the figure.
|
|
115
|
+
* @param legend - The card, as it sits on the page.
|
|
116
|
+
* @param box - Its box, so the pieces inside it can be placed against it.
|
|
117
|
+
* @returns Its markup, in the card's own coordinates.
|
|
118
|
+
*/
|
|
119
|
+
function legendMarkup(legend: Element, box: DOMRect): string {
|
|
120
|
+
const ground = legend.firstElementChild;
|
|
121
|
+
const styles = ground === null ? undefined : window.getComputedStyle(ground);
|
|
122
|
+
|
|
123
|
+
const marks: FigureLegendMark[] = [];
|
|
124
|
+
for (const mark of legend.querySelectorAll('svg')) {
|
|
125
|
+
const at = mark.getBoundingClientRect();
|
|
126
|
+
marks.push({
|
|
127
|
+
markup: drawingMarkup(mark),
|
|
128
|
+
x: at.left - box.left,
|
|
129
|
+
y: at.top - box.top,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const texts: FigureLegendText[] = [];
|
|
134
|
+
for (const run of legend.querySelectorAll('*')) {
|
|
135
|
+
if (run.firstElementChild !== null) continue;
|
|
136
|
+
const words = run.textContent?.trim() ?? '';
|
|
137
|
+
if (words === '') continue;
|
|
138
|
+
const at = run.getBoundingClientRect();
|
|
139
|
+
const type = window.getComputedStyle(run);
|
|
140
|
+
texts.push({
|
|
141
|
+
text: words,
|
|
142
|
+
x: at.left - box.left,
|
|
143
|
+
y: at.top - box.top + at.height / 2,
|
|
144
|
+
color: type.color,
|
|
145
|
+
fontSize: Number.parseFloat(type.fontSize),
|
|
146
|
+
fontWeight: type.fontWeight,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return figureLegendMarkup({
|
|
151
|
+
card: {
|
|
152
|
+
width: box.width,
|
|
153
|
+
height: box.height,
|
|
154
|
+
radius:
|
|
155
|
+
styles === undefined
|
|
156
|
+
? 0
|
|
157
|
+
: Number.parseFloat(styles.borderTopLeftRadius),
|
|
158
|
+
background: styles?.backgroundColor,
|
|
159
|
+
border: styles?.borderTopColor,
|
|
160
|
+
borderWidth:
|
|
161
|
+
styles === undefined ? 1 : Number.parseFloat(styles.borderTopWidth),
|
|
162
|
+
},
|
|
163
|
+
marks,
|
|
164
|
+
texts,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
88
168
|
/**
|
|
89
169
|
* One drawing, serialized with every token it names written out.
|
|
90
170
|
*
|
|
@@ -12,14 +12,21 @@
|
|
|
12
12
|
* that decides what the file *is* can be read without a DOM to run it in.
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
/** One
|
|
15
|
+
/** One piece of the page, and where it sits inside the saved figure. */
|
|
16
16
|
export interface FigurePiece {
|
|
17
|
-
/** The
|
|
17
|
+
/** The markup, tokens already resolved. */
|
|
18
18
|
markup: string;
|
|
19
19
|
/** Its left edge, in pixels from the left of the saved figure. */
|
|
20
20
|
x: number;
|
|
21
21
|
/** Its top edge, in pixels from the top of the saved figure. */
|
|
22
22
|
y: number;
|
|
23
|
+
/**
|
|
24
|
+
* What it is. Written into the file, so a reader — a test, or somebody
|
|
25
|
+
* editing the figure afterwards — can tell the drawings from the key that
|
|
26
|
+
* was painted over them.
|
|
27
|
+
* @default 'drawing'
|
|
28
|
+
*/
|
|
29
|
+
kind?: 'drawing' | 'legend';
|
|
23
30
|
}
|
|
24
31
|
|
|
25
32
|
/** How the file around the drawings is written. */
|
|
@@ -71,7 +78,10 @@ export function figureSvgDocument(
|
|
|
71
78
|
? ''
|
|
72
79
|
: `<rect width="100%" height="100%" fill="${escapeAttribute(background)}"/>`;
|
|
73
80
|
for (const piece of pieces) {
|
|
74
|
-
|
|
81
|
+
const kind = piece.kind ?? 'drawing';
|
|
82
|
+
inside +=
|
|
83
|
+
`<g data-figure="${kind}" transform="translate(${round(piece.x)} ${round(piece.y)})">` +
|
|
84
|
+
`${piece.markup}</g>`;
|
|
75
85
|
}
|
|
76
86
|
|
|
77
87
|
return (
|
|
@@ -13,6 +13,9 @@ import type { FigurePixels } from './figureScale.ts';
|
|
|
13
13
|
/** Chrome floating over a figure, which is not part of the picture. */
|
|
14
14
|
const CHROME = '[data-figure="chrome"]';
|
|
15
15
|
|
|
16
|
+
/** A key floating over a figure, which is. */
|
|
17
|
+
const LEGEND = '[data-figure="legend"]';
|
|
18
|
+
|
|
16
19
|
/** A figure's box on the page, in the coordinates a bounding box reports. */
|
|
17
20
|
export interface FigureBounds {
|
|
18
21
|
/** Its left edge. */
|
|
@@ -70,6 +73,24 @@ export function figureDrawings(element: Element): readonly SVGSVGElement[] {
|
|
|
70
73
|
return drawings;
|
|
71
74
|
}
|
|
72
75
|
|
|
76
|
+
/**
|
|
77
|
+
* The keys inside it.
|
|
78
|
+
*
|
|
79
|
+
* A key is chrome — it is a filter the reader presses — and is therefore not
|
|
80
|
+
* among the drawings, but it is still part of the picture: a saved figure
|
|
81
|
+
* whose colours stand for nothing is not a figure. So it is collected
|
|
82
|
+
* separately, to be redrawn over the drawings rather than copied with them.
|
|
83
|
+
* @param element - The box the figure is mounted in.
|
|
84
|
+
* @returns The keys, in the order they are painted.
|
|
85
|
+
*/
|
|
86
|
+
export function figureLegends(element: Element): readonly Element[] {
|
|
87
|
+
const legends: Element[] = [];
|
|
88
|
+
for (const legend of element.querySelectorAll(LEGEND)) {
|
|
89
|
+
legends.push(legend);
|
|
90
|
+
}
|
|
91
|
+
return legends;
|
|
92
|
+
}
|
|
93
|
+
|
|
73
94
|
/**
|
|
74
95
|
* The box every drawing of a figure fits in.
|
|
75
96
|
* @param drawings - The drawings, as they sit on the page.
|