@terraware/web-components 5.0.26-rc.1 → 5.0.27-rc.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/components/AntSwitch/index.js +19 -22
- package/components/Autocomplete/Autocomplete.js +106 -130
- package/components/Badge/index.js +28 -29
- package/components/BusySpinner/index.js +40 -45
- package/components/Button/Button.js +41 -47
- package/components/Checkbox.js +64 -63
- package/components/Confirm/index.js +74 -83
- package/components/DatePicker/DatePicker.js +138 -141
- package/components/DialogBox/DialogBox.js +111 -118
- package/components/Divisor.js +18 -18
- package/components/Dropdown.js +66 -94
- package/components/EditableTable/index.js +211 -271
- package/components/ErrorBox/ErrorBox.js +47 -49
- package/components/FileChooser/index.js +117 -135
- package/components/FormBottomBar/index.js +75 -84
- package/components/Icon/Icon.js +12 -20
- package/components/Icon/icons/index.js +256 -256
- package/components/IconTooltip/index.js +49 -60
- package/components/Map/MapBox.js +545 -452
- package/components/Map/MapContainer.js +25 -29
- package/components/Map/MapDateSliderControl.js +64 -64
- package/components/Map/MapDrawer.js +41 -47
- package/components/Map/MapLegend.js +176 -172
- package/components/Map/MapViewStyleControl.js +59 -63
- package/components/Map/ReactMapboxWrapper.js +3 -2
- package/components/Map/index.js +161 -180
- package/components/Map/types.js +12 -17
- package/components/Map/useMaintainLayerOrder.js +16 -26
- package/components/Markdown/index.js +25 -26
- package/components/Message/Message.js +73 -76
- package/components/MultiSelect/index.js +112 -124
- package/components/Navbar/NavFooter.js +9 -13
- package/components/Navbar/NavItem.js +70 -76
- package/components/Navbar/NavSection.js +17 -19
- package/components/Navbar/Navbar.js +39 -46
- package/components/Navbar/SubNavbar.js +9 -13
- package/components/Note.js +18 -22
- package/components/OverlayModal/OverlayModal.js +56 -63
- package/components/PageForm/index.js +33 -41
- package/components/PhotoChooser/index.js +165 -173
- package/components/PhotosCarousel/PhotoSlide.js +32 -35
- package/components/PhotosCarousel/index.js +80 -85
- package/components/PhotosCarousel/usePhotosCarousel.js +69 -76
- package/components/Pill/index.js +41 -45
- package/components/PillList/index.js +17 -24
- package/components/PlacementWrapper/index.js +38 -59
- package/components/PopoverMenu/Popover.js +68 -85
- package/components/PopoverMenu/index.js +51 -56
- package/components/PopoverMultiSelect/index.js +52 -59
- package/components/ProgressCircle/ProgressCircle.js +28 -32
- package/components/RadioButton.js +17 -19
- package/components/Select/Select.js +13 -15
- package/components/Select/SelectT.js +235 -250
- package/components/Separator/index.js +14 -17
- package/components/Size.js +0 -1
- package/components/Slider/index.js +43 -56
- package/components/SummaryBox.js +70 -72
- package/components/Tabs/index.js +133 -135
- package/components/TextTruncated/index.js +117 -130
- package/components/Textfield/Textfield.js +158 -190
- package/components/Textfield/TruncatedTextArea.js +70 -84
- package/components/TimelineSlider/TimelineMarker.js +25 -30
- package/components/TimelineSlider/TimelineRail.js +8 -11
- package/components/TimelineSlider/index.js +64 -66
- package/components/TimelineSliderV2/ClusterBadge.js +25 -29
- package/components/TimelineSliderV2/TimelineDot.js +31 -35
- package/components/TimelineSliderV2/TimelineRail.js +8 -11
- package/components/TimelineSliderV2/index.js +121 -103
- package/components/TimelineSliderV2/layout.js +124 -147
- package/components/TimelineSliderV2/types.js +0 -1
- package/components/Tooltip/Tooltip.js +47 -56
- package/components/ViewPhotosDialog/index.js +28 -35
- package/components/VirtualWalkthrough/Annotation.js +163 -207
- package/components/VirtualWalkthrough/AnnotationEditPane.js +198 -184
- package/components/VirtualWalkthrough/AnnotationPanel.js +187 -199
- package/components/VirtualWalkthrough/Application.js +31 -34
- package/components/VirtualWalkthrough/AutoRotator.js +85 -223
- package/components/VirtualWalkthrough/BlockingSpinner.js +26 -28
- package/components/VirtualWalkthrough/BoundaryRing.js +30 -34
- package/components/VirtualWalkthrough/BoundaryWall.js +32 -36
- package/components/VirtualWalkthrough/CameraInfo.js +100 -89
- package/components/VirtualWalkthrough/ControlsInfoPane.js +254 -195
- package/components/VirtualWalkthrough/GradientSky.js +72 -73
- package/components/VirtualWalkthrough/SplatControls.js +209 -221
- package/components/VirtualWalkthrough/SplatCrop.js +21 -20
- package/components/VirtualWalkthrough/SplatFadeCrop.js +21 -20
- package/components/VirtualWalkthrough/SplatModel.js +65 -85
- package/components/VirtualWalkthrough/SplatRevealRain.js +41 -46
- package/components/VirtualWalkthrough/TfAnnotationManager.js +197 -379
- package/components/VirtualWalkthrough/TfXrNavigation.js +73 -162
- package/components/VirtualWalkthrough/VirtualWalkthroughViewer.js +438 -431
- package/components/VirtualWalkthrough/VrAnnotationPanel.js +18 -22
- package/components/VirtualWalkthrough/XrAnnotationInteraction.js +14 -17
- package/components/VirtualWalkthrough/XrExitButton.js +14 -17
- package/components/VirtualWalkthrough/XrGazeDwell.js +14 -17
- package/components/VirtualWalkthrough/XrPointerRay.js +14 -17
- package/components/VirtualWalkthrough/XrStartPose.js +67 -121
- package/components/VirtualWalkthrough/boundary-ring.js +87 -117
- package/components/VirtualWalkthrough/boundary-wall.js +175 -258
- package/components/VirtualWalkthrough/camera-adoption.js +18 -64
- package/components/VirtualWalkthrough/groundPlane.js +32 -47
- package/components/VirtualWalkthrough/gsplat-fade-crop-effect.js +35 -35
- package/components/VirtualWalkthrough/splatFormat.js +13 -47
- package/components/VirtualWalkthrough/useAdoptedCamera.js +23 -44
- package/components/VirtualWalkthrough/useRestartOnVr.js +26 -37
- package/components/VirtualWalkthrough/useXrRenderTuning.js +33 -54
- package/components/VirtualWalkthrough/vr-annotation-panel-layout.js +67 -99
- package/components/VirtualWalkthrough/vr-annotation-panel.js +403 -433
- package/components/VirtualWalkthrough/vr-annotation-scroll.js +10 -28
- package/components/VirtualWalkthrough/walkthrough-camera.js +204 -329
- package/components/VirtualWalkthrough/xr-annotation-candidate-buffer.js +39 -80
- package/components/VirtualWalkthrough/xr-annotation-candidates.js +6 -18
- package/components/VirtualWalkthrough/xr-annotation-interaction.js +31 -56
- package/components/VirtualWalkthrough/xr-annotation-targeting.js +22 -38
- package/components/VirtualWalkthrough/xr-button-arming.js +7 -17
- package/components/VirtualWalkthrough/xr-button-hold.js +22 -36
- package/components/VirtualWalkthrough/xr-exit-button-mask.js +22 -36
- package/components/VirtualWalkthrough/xr-exit-button.js +148 -207
- package/components/VirtualWalkthrough/xr-face-buttons.js +19 -29
- package/components/VirtualWalkthrough/xr-gaze-dwell-state.js +23 -34
- package/components/VirtualWalkthrough/xr-gaze-dwell.js +107 -144
- package/components/VirtualWalkthrough/xr-interactive-ui.js +12 -24
- package/components/VirtualWalkthrough/xr-pointer-ray.js +13 -20
- package/components/VirtualWalkthrough/xr-progress-pie-material.js +117 -88
- package/components/VirtualWalkthrough/xr-progress-pie.js +1 -10
- package/components/VirtualWalkthrough/xr-ray-quad.js +16 -30
- package/components/VirtualWalkthrough/xr-render-tuning.js +17 -48
- package/components/VirtualWalkthrough/xr-scene-bounds.js +21 -37
- package/components/VirtualWalkthrough/xr-start-pose.js +27 -73
- package/components/VirtualWalkthrough/xr-teleport-gesture.js +16 -42
- package/components/svg/BlobbyGrayIconImage.js +41 -39
- package/components/svg/BlobbyGrayIconImport.js +41 -39
- package/components/svg/BlobbyGrayIconUploadToTheCloud.js +41 -39
- package/components/svg/BlobbyIconCloudChecked.js +202 -164
- package/components/svg/BlobbyIconExportOrUploadPhoto.js +202 -164
- package/components/svg/BlobbyIconFolder.js +202 -164
- package/components/svg/BlobbyIconGraphReport.js +202 -164
- package/components/svg/BlobbyIconHappy.js +202 -164
- package/components/svg/BlobbyIconHeartMonitor.js +202 -164
- package/components/svg/BlobbyIconLeaf.js +202 -164
- package/components/svg/BlobbyIconLibrary.js +202 -164
- package/components/svg/BlobbyIconNursery.js +204 -166
- package/components/svg/BlobbyIconOrganization.js +202 -164
- package/components/svg/BlobbyIconParchment.js +202 -164
- package/components/svg/BlobbyIconPeople.js +202 -164
- package/components/svg/BlobbyIconSeedBank.js +202 -164
- package/components/svg/BlobbyIconSeedling.js +202 -164
- package/components/svg/BlobbyIconSeeds.js +202 -164
- package/components/svg/BlobbyIconSite.js +206 -167
- package/components/svg/BlobbyIconSparkles.js +202 -164
- package/components/svg/BlobbyIconWrench.js +202 -164
- package/components/svg/Bug.js +19 -21
- package/components/svg/Calendar.js +19 -21
- package/components/svg/CaretDown.js +19 -21
- package/components/svg/CaretLeft.js +19 -21
- package/components/svg/CaretRight.js +19 -21
- package/components/svg/CaretUp.js +19 -21
- package/components/svg/ChevronDown.js +19 -21
- package/components/svg/ChevronUp.js +19 -21
- package/components/svg/Close.js +19 -21
- package/components/svg/Critical.js +19 -21
- package/components/svg/Edit.js +202 -164
- package/components/svg/Error.js +19 -21
- package/components/svg/Filter.js +19 -21
- package/components/svg/Folder.js +19 -21
- package/components/svg/Help.js +19 -21
- package/components/svg/Home.js +19 -21
- package/components/svg/IconAdd.js +19 -21
- package/components/svg/IconArrowRight.js +21 -23
- package/components/svg/IconBusinessNetwork.js +19 -21
- package/components/svg/IconCalendar.js +19 -21
- package/components/svg/IconCancel.js +19 -21
- package/components/svg/IconChargingBattery.js +19 -21
- package/components/svg/IconChecklist.js +21 -23
- package/components/svg/IconCheckmark.js +19 -21
- package/components/svg/IconCoinInHand.js +19 -21
- package/components/svg/IconColumns.js +19 -21
- package/components/svg/IconComment.js +20 -22
- package/components/svg/IconDashboard.js +19 -21
- package/components/svg/IconDataMigration.js +19 -21
- package/components/svg/IconDocument.js +21 -23
- package/components/svg/IconDownloadFromTheCloud.js +21 -23
- package/components/svg/IconEdit.js +21 -23
- package/components/svg/IconExpand.js +21 -23
- package/components/svg/IconExport.js +19 -21
- package/components/svg/IconExternalLink.js +19 -21
- package/components/svg/IconEye.js +19 -21
- package/components/svg/IconEyeOff.js +19 -21
- package/components/svg/IconFile.js +19 -21
- package/components/svg/IconFolder.js +19 -21
- package/components/svg/IconFullScreen.js +20 -22
- package/components/svg/IconFutures.js +19 -21
- package/components/svg/IconGraphReport.js +19 -21
- package/components/svg/IconGrid.js +19 -21
- package/components/svg/IconHeartMonitor.js +19 -21
- package/components/svg/IconHelp.js +21 -23
- package/components/svg/IconHistory.js +19 -21
- package/components/svg/IconImport.js +19 -21
- package/components/svg/IconIndex.js +19 -21
- package/components/svg/IconLayers.js +19 -21
- package/components/svg/IconLibrary.js +20 -22
- package/components/svg/IconList.js +19 -21
- package/components/svg/IconLivePlant.js +19 -21
- package/components/svg/IconLocations.js +19 -21
- package/components/svg/IconMail.js +19 -21
- package/components/svg/IconManager.js +19 -21
- package/components/svg/IconMap.js +19 -21
- package/components/svg/IconMarker.js +19 -21
- package/components/svg/IconMenu.js +19 -21
- package/components/svg/IconMenuHorizontal.js +19 -21
- package/components/svg/IconModule.js +19 -21
- package/components/svg/IconMyLocation.js +19 -21
- package/components/svg/IconNote.js +21 -23
- package/components/svg/IconNursery.js +21 -23
- package/components/svg/IconOrg.js +19 -21
- package/components/svg/IconParchment.js +19 -21
- package/components/svg/IconPhoto.js +19 -21
- package/components/svg/IconPlantsFilled.js +19 -21
- package/components/svg/IconRedo.js +19 -21
- package/components/svg/IconRestorationSite.js +19 -21
- package/components/svg/IconSeedBank.js +19 -21
- package/components/svg/IconSeedling.js +19 -21
- package/components/svg/IconSettings.js +19 -21
- package/components/svg/IconSlice.js +19 -21
- package/components/svg/IconSubmit.js +19 -21
- package/components/svg/IconSubtract.js +21 -23
- package/components/svg/IconSynced.js +19 -21
- package/components/svg/IconTrashCan.js +19 -21
- package/components/svg/IconTreasureMap.js +19 -21
- package/components/svg/IconUnavailable.js +19 -21
- package/components/svg/IconUndo.js +19 -21
- package/components/svg/IconVariable.js +19 -21
- package/components/svg/IconVideo.js +30 -31
- package/components/svg/IconWifi.js +19 -21
- package/components/svg/Info.js +19 -21
- package/components/svg/Key.js +19 -21
- package/components/svg/Leaf.js +19 -21
- package/components/svg/Lock.js +19 -21
- package/components/svg/Logo.js +48 -43
- package/components/svg/MenuVertical.js +19 -21
- package/components/svg/Notification.js +19 -21
- package/components/svg/Person.js +19 -21
- package/components/svg/Plus.js +19 -21
- package/components/svg/RestorationSite.js +19 -21
- package/components/svg/Search.js +19 -21
- package/components/svg/Seeds.js +19 -21
- package/components/svg/Site.js +19 -21
- package/components/svg/Sparkles.js +19 -21
- package/components/svg/Species.js +19 -21
- package/components/svg/Species2.js +202 -164
- package/components/svg/Spinner.js +54 -48
- package/components/svg/Star.js +19 -21
- package/components/svg/Success.js +19 -21
- package/components/svg/SuccessFilled.js +19 -21
- package/components/svg/TerrawareLogoDesktop.js +55 -49
- package/components/svg/TerrawareLogoMobile.js +25 -26
- package/components/svg/Touchscreen.js +19 -21
- package/components/svg/UploadCloud.js +202 -164
- package/components/svg/Warning.js +19 -21
- package/components/svg/WelcomeClipboard.js +156 -133
- package/components/svg/index.js +129 -129
- package/components/table/EnhancedTableToolbar.js +68 -74
- package/components/table/EnhancedTableToolbarV2.js +31 -41
- package/components/table/TableCellRenderer.js +196 -231
- package/components/table/TableHeader.js +71 -73
- package/components/table/TableHeaderItem.js +97 -102
- package/components/table/density.js +18 -19
- package/components/table/index.js +350 -369
- package/components/table/sort.js +27 -52
- package/components/table/types.js +0 -1
- package/components/types/index.js +0 -1
- package/hooks/cameraEntityContext.js +2 -13
- package/hooks/useBoolean.js +17 -13
- package/hooks/useCameraPosition.js +56 -56
- package/hooks/useDevicePerformance.js +17 -17
- package/hooks/useXr.js +85 -87
- package/index.js +58 -58
- package/license-report.html +1 -1
- package/package.json +3 -3
- package/setupTests.js +0 -4
- package/strings/export.js +111 -170
- package/strings/index.js +25 -54
- package/strings/locales.js +21 -41
- package/strings/strings-en.js +49 -51
- package/strings/strings-es.js +49 -51
- package/strings/strings-fr.js +49 -51
- package/strings/strings-gx.js +49 -51
- package/style-dictionary-dist/TerrawareTheme.js +186 -186
- package/theme.js +74 -76
- package/utils/color.js +8 -15
- package/utils/date.js +42 -108
- package/utils/index.js +4 -4
- package/utils/preventDefaultEvent.js +3 -3
- package/utils/text.js +11 -11
- package/utils/useDeviceInfo.js +42 -79
- package/virtualWalkthrough.js +23 -23
|
@@ -1,88 +1,47 @@
|
|
|
1
|
-
import { Vec3 } from
|
|
2
|
-
|
|
3
|
-
/** Local half-extent of the unit-plane hotspot quad. */
|
|
1
|
+
import { Vec3 } from "playcanvas";
|
|
4
2
|
const HOTSPOT_HALF_EXTENT = 0.5;
|
|
5
|
-
|
|
6
|
-
/** Pulls the stock annotation script off a hotspot entity, or undefined if it carries none. */
|
|
7
|
-
|
|
8
3
|
const scratchScale = new Vec3();
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
* keeps its own `children` array - a destroyed one keeps it as an empty array - so only a walk back
|
|
13
|
-
* up the parent chain tells a live root apart from a detached one.
|
|
14
|
-
*/
|
|
15
|
-
const isInScene = (node, sceneRoot) => {
|
|
16
|
-
for (let current = node; current; current = current.parent) {
|
|
17
|
-
if (current === sceneRoot) {
|
|
18
|
-
return true;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
return false;
|
|
4
|
+
const isInScene = (node, sceneRoot)=>{
|
|
5
|
+
for(let current = node; current; current = current.parent)if (current === sceneRoot) return true;
|
|
6
|
+
return false;
|
|
22
7
|
};
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Collects world-space hit candidates for the openable annotation hotspots into a buffer it owns and
|
|
26
|
-
* reuses, so a caller running every frame allocates nothing. The returned array and the candidate
|
|
27
|
-
* objects inside it are overwritten by the next `collect`, which is why each caller holds its own
|
|
28
|
-
* buffer rather than sharing one.
|
|
29
|
-
*
|
|
30
|
-
* Positions and radii are re-read on every call, so hotspots that move or resize stay targetable.
|
|
31
|
-
* That read is cheap; it is the allocation around it that a per-frame caller cannot afford.
|
|
32
|
-
*/
|
|
33
8
|
class AnnotationCandidateBuffer {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Hit candidates for every openable hotspot except `excludeName`, with hit spheres derived from
|
|
42
|
-
* each hotspot's rendered world size and padded by `radiusPad` for easier aiming.
|
|
43
|
-
*/
|
|
44
|
-
collect(app, radiusPad, excludeName) {
|
|
45
|
-
// The root is looked up by a walk of the whole scene graph, so it is held onto between frames.
|
|
46
|
-
// It is re-resolved whenever it leaves the scene: annotations mount after the scene does, and
|
|
47
|
-
// the root is torn down and built afresh every time the annotation list empties and refills.
|
|
48
|
-
if (!isInScene(this._root, app.root)) {
|
|
49
|
-
this._root = app.root.findByName('annotations-root');
|
|
50
|
-
}
|
|
51
|
-
const children = this._root?.children;
|
|
52
|
-
if (!children) {
|
|
53
|
-
this._candidates.length = 0;
|
|
54
|
-
return this._candidates;
|
|
9
|
+
_getScript;
|
|
10
|
+
_candidates = [];
|
|
11
|
+
_root = null;
|
|
12
|
+
constructor(_getScript){
|
|
13
|
+
this._getScript = _getScript;
|
|
55
14
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
15
|
+
collect(app, radiusPad, excludeName) {
|
|
16
|
+
if (!isInScene(this._root, app.root)) this._root = app.root.findByName('annotations-root');
|
|
17
|
+
const children = this._root?.children;
|
|
18
|
+
if (!children) {
|
|
19
|
+
this._candidates.length = 0;
|
|
20
|
+
return this._candidates;
|
|
21
|
+
}
|
|
22
|
+
let count = 0;
|
|
23
|
+
for (const entity of children){
|
|
24
|
+
if (void 0 !== excludeName && entity.name === excludeName) continue;
|
|
25
|
+
const script = this._getScript(entity);
|
|
26
|
+
if (!script || false === script.enabled || 'function' != typeof script.onVrOpenCallback) continue;
|
|
27
|
+
entity.getWorldTransform().getScale(scratchScale);
|
|
28
|
+
const radius = HOTSPOT_HALF_EXTENT * scratchScale.x * radiusPad;
|
|
29
|
+
const existing = this._candidates[count];
|
|
30
|
+
if (existing) {
|
|
31
|
+
existing.entity = entity;
|
|
32
|
+
existing.script = script;
|
|
33
|
+
existing.position = entity.getPosition();
|
|
34
|
+
existing.radius = radius;
|
|
35
|
+
} else this._candidates.push({
|
|
36
|
+
entity,
|
|
37
|
+
script,
|
|
38
|
+
position: entity.getPosition(),
|
|
39
|
+
radius
|
|
40
|
+
});
|
|
41
|
+
count++;
|
|
42
|
+
}
|
|
43
|
+
this._candidates.length = count;
|
|
44
|
+
return this._candidates;
|
|
82
45
|
}
|
|
83
|
-
this._candidates.length = count;
|
|
84
|
-
return this._candidates;
|
|
85
|
-
}
|
|
86
46
|
}
|
|
87
|
-
|
|
88
47
|
export { AnnotationCandidateBuffer, HOTSPOT_HALF_EXTENT };
|
|
@@ -1,19 +1,7 @@
|
|
|
1
|
-
import { Annotation } from
|
|
2
|
-
import { AnnotationCandidateBuffer } from
|
|
3
|
-
export { HOTSPOT_HALF_EXTENT } from './xr-annotation-candidate-buffer.js';
|
|
4
|
-
|
|
5
|
-
/** Multiplier on the hotspot's world radius to make controller targeting forgiving. */
|
|
1
|
+
import { Annotation } from "playcanvas/scripts/esm/annotations.mjs";
|
|
2
|
+
import { AnnotationCandidateBuffer, HOTSPOT_HALF_EXTENT } from "./xr-annotation-candidate-buffer.js";
|
|
6
3
|
const HIT_RADIUS_PAD = 2.5;
|
|
7
|
-
const annotationScriptOf = entity
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const createAnnotationCandidateBuffer = () => new AnnotationCandidateBuffer(annotationScriptOf);
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* One-shot collection for callers that run on an input event rather than every frame, and so have no
|
|
15
|
-
* reason to hold a buffer of their own.
|
|
16
|
-
*/
|
|
17
|
-
const collectAnnotationHitCandidates = (app, radiusPad) => createAnnotationCandidateBuffer().collect(app, radiusPad);
|
|
18
|
-
|
|
19
|
-
export { HIT_RADIUS_PAD, collectAnnotationHitCandidates, createAnnotationCandidateBuffer };
|
|
4
|
+
const annotationScriptOf = (entity)=>entity.script?.get(Annotation.scriptName);
|
|
5
|
+
const createAnnotationCandidateBuffer = ()=>new AnnotationCandidateBuffer(annotationScriptOf);
|
|
6
|
+
const collectAnnotationHitCandidates = (app, radiusPad)=>createAnnotationCandidateBuffer().collect(app, radiusPad);
|
|
7
|
+
export { HIT_RADIUS_PAD, HOTSPOT_HALF_EXTENT, collectAnnotationHitCandidates, createAnnotationCandidateBuffer };
|
|
@@ -1,62 +1,37 @@
|
|
|
1
|
-
import { Script, XRTYPE_VR } from
|
|
2
|
-
import {
|
|
3
|
-
import { nearestAnnotationHit } from
|
|
4
|
-
import { FaceButtonPressTracker } from
|
|
5
|
-
import { rayHitsAnnotationPanel } from
|
|
6
|
-
|
|
1
|
+
import { Script, XRTYPE_VR } from "playcanvas";
|
|
2
|
+
import { HIT_RADIUS_PAD, collectAnnotationHitCandidates } from "./xr-annotation-candidates.js";
|
|
3
|
+
import { nearestAnnotationHit } from "./xr-annotation-targeting.js";
|
|
4
|
+
import { FaceButtonPressTracker } from "./xr-face-buttons.js";
|
|
5
|
+
import { rayHitsAnnotationPanel } from "./xr-interactive-ui.js";
|
|
7
6
|
class XrAnnotationInteraction extends Script {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
static scriptName = 'xrAnnotationInteraction';
|
|
8
|
+
onDismissCallback;
|
|
9
|
+
_faceButtons = new FaceButtonPressTracker();
|
|
10
|
+
_isVrActive = ()=>this.app.xr?.active === true && this.app.xr?.type === XRTYPE_VR;
|
|
11
|
+
_dismiss = ()=>{
|
|
12
|
+
if ('function' == typeof this.onDismissCallback) this.onDismissCallback();
|
|
13
|
+
};
|
|
14
|
+
_onSelect = (inputSource)=>{
|
|
15
|
+
if (!this._isVrActive()) return;
|
|
16
|
+
this._openAnnotationUnderRay(inputSource.getOrigin(), inputSource.getDirection());
|
|
17
|
+
};
|
|
18
|
+
_openAnnotationUnderRay(origin, direction) {
|
|
19
|
+
if (rayHitsAnnotationPanel(this.app, origin, direction)) return;
|
|
20
|
+
const candidates = collectAnnotationHitCandidates(this.app, HIT_RADIUS_PAD);
|
|
21
|
+
const index = nearestAnnotationHit(origin, direction, candidates);
|
|
22
|
+
if (null === index) return void this._dismiss();
|
|
23
|
+
const { entity, script } = candidates[index];
|
|
24
|
+
const camera = this.app.root.findComponent('camera');
|
|
25
|
+
const screen = camera?.worldToScreen(entity.getPosition());
|
|
26
|
+
script.onVrOpenCallback(screen?.x ?? 0, screen?.y ?? 0);
|
|
14
27
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
return;
|
|
28
|
+
initialize() {
|
|
29
|
+
this.app.xr?.input?.on('select', this._onSelect);
|
|
30
|
+
this.once('destroy', ()=>this.app.xr?.input?.off('select', this._onSelect));
|
|
19
31
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
// Checked before the hotspots so aiming at the panel (e.g. its carousel arrows) neither
|
|
24
|
-
// dismisses it nor opens an annotation whose padded hit sphere sits behind it.
|
|
25
|
-
if (rayHitsAnnotationPanel(this.app, origin, direction)) {
|
|
26
|
-
return;
|
|
32
|
+
update() {
|
|
33
|
+
if (!this._isVrActive()) return;
|
|
34
|
+
for (const inputSource of this.app.xr?.input?.inputSources ?? [])if (this._faceButtons.justPressed(inputSource)) return void this._dismiss();
|
|
27
35
|
}
|
|
28
|
-
const candidates = collectAnnotationHitCandidates(this.app, HIT_RADIUS_PAD);
|
|
29
|
-
const index = nearestAnnotationHit(origin, direction, candidates);
|
|
30
|
-
if (index === null) {
|
|
31
|
-
this._dismiss();
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
const {
|
|
35
|
-
entity,
|
|
36
|
-
script
|
|
37
|
-
} = candidates[index];
|
|
38
|
-
const camera = this.app.root.findComponent('camera');
|
|
39
|
-
const screen = camera?.worldToScreen(entity.getPosition());
|
|
40
|
-
script.onVrOpenCallback(screen?.x ?? 0, screen?.y ?? 0);
|
|
41
|
-
}
|
|
42
|
-
initialize() {
|
|
43
|
-
this.app.xr?.input?.on('select', this._onSelect);
|
|
44
|
-
this.once('destroy', () => this.app.xr?.input?.off('select', this._onSelect));
|
|
45
|
-
}
|
|
46
|
-
update() {
|
|
47
|
-
if (!this._isVrActive()) {
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// A face button dismisses from any aim direction, unlike the click-out select. Harmless when
|
|
52
|
-
// nothing is open: the React close handler re-sets state it already holds.
|
|
53
|
-
for (const inputSource of this.app.xr?.input?.inputSources ?? []) {
|
|
54
|
-
if (this._faceButtons.justPressed(inputSource)) {
|
|
55
|
-
this._dismiss();
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
36
|
}
|
|
61
|
-
|
|
62
37
|
export { XrAnnotationInteraction };
|
|
@@ -1,44 +1,28 @@
|
|
|
1
|
-
import { Vec3 } from
|
|
2
|
-
|
|
3
|
-
// Reused across calls: this runs per candidate per frame, where fresh vectors would be steady GC churn.
|
|
1
|
+
import { Vec3 } from "playcanvas";
|
|
4
2
|
const scratchDir = new Vec3();
|
|
5
3
|
const scratchToCenter = new Vec3();
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if (c > 0 && b > 0) {
|
|
16
|
-
return null;
|
|
17
|
-
}
|
|
18
|
-
const disc = b * b - c;
|
|
19
|
-
if (disc < 0) {
|
|
20
|
-
return null;
|
|
21
|
-
}
|
|
22
|
-
const t = -b - Math.sqrt(disc);
|
|
23
|
-
return t < 0 ? 0 : t;
|
|
4
|
+
const raySphereEntryDistance = (origin, dir, center, radius)=>{
|
|
5
|
+
const m = scratchToCenter.sub2(origin, center);
|
|
6
|
+
const b = m.dot(dir);
|
|
7
|
+
const c = m.dot(m) - radius * radius;
|
|
8
|
+
if (c > 0 && b > 0) return null;
|
|
9
|
+
const disc = b * b - c;
|
|
10
|
+
if (disc < 0) return null;
|
|
11
|
+
const t = -b - Math.sqrt(disc);
|
|
12
|
+
return t < 0 ? 0 : t;
|
|
24
13
|
};
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if (distance !== null && distance < bestDistance) {
|
|
37
|
-
bestDistance = distance;
|
|
38
|
-
bestIndex = index;
|
|
14
|
+
const nearestAnnotationHit = (origin, direction, candidates)=>{
|
|
15
|
+
const dir = scratchDir.copy(direction).normalize();
|
|
16
|
+
let bestIndex = null;
|
|
17
|
+
let bestDistance = 1 / 0;
|
|
18
|
+
for(let index = 0; index < candidates.length; index++){
|
|
19
|
+
const candidate = candidates[index];
|
|
20
|
+
const distance = raySphereEntryDistance(origin, dir, candidate.position, candidate.radius);
|
|
21
|
+
if (null !== distance && distance < bestDistance) {
|
|
22
|
+
bestDistance = distance;
|
|
23
|
+
bestIndex = index;
|
|
24
|
+
}
|
|
39
25
|
}
|
|
40
|
-
|
|
41
|
-
return bestIndex;
|
|
26
|
+
return bestIndex;
|
|
42
27
|
};
|
|
43
|
-
|
|
44
28
|
export { nearestAnnotationHit };
|
|
@@ -1,21 +1,11 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Latches per input source whether a press may count toward a hold. A source arms itself the
|
|
3
|
-
* moment it is seen released, and stays armed from then on - so a button already down when
|
|
4
|
-
* tracking starts is ignored until it is released once, and one controller held down can't stop
|
|
5
|
-
* another from arming and counting. Callers must poll every frame for every source they care
|
|
6
|
-
* about; a press and release between polls is missed.
|
|
7
|
-
*/
|
|
8
1
|
class ButtonArmingLatch {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
2
|
+
_armed = new WeakSet();
|
|
3
|
+
trackPress(inputSource, pressed) {
|
|
4
|
+
if (!pressed) {
|
|
5
|
+
this._armed.add(inputSource);
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
return this._armed.has(inputSource);
|
|
16
9
|
}
|
|
17
|
-
return this._armed.has(inputSource);
|
|
18
|
-
}
|
|
19
10
|
}
|
|
20
|
-
|
|
21
11
|
export { ButtonArmingLatch };
|
|
@@ -1,45 +1,31 @@
|
|
|
1
1
|
const INITIAL_HOLD_STATE = {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
elapsed: 0,
|
|
3
|
+
armed: false
|
|
4
4
|
};
|
|
5
5
|
const RELEASED_STATE = {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
elapsed: 0,
|
|
7
|
+
armed: true
|
|
8
8
|
};
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
if (!held) {
|
|
20
|
-
return {
|
|
21
|
-
state: RELEASED_STATE,
|
|
22
|
-
progress: 0,
|
|
23
|
-
justFired: false
|
|
9
|
+
const advanceHold = (prev, held, dt, threshold)=>{
|
|
10
|
+
if (!held) return {
|
|
11
|
+
state: RELEASED_STATE,
|
|
12
|
+
progress: 0,
|
|
13
|
+
justFired: false
|
|
14
|
+
};
|
|
15
|
+
if (!prev.armed) return {
|
|
16
|
+
state: prev,
|
|
17
|
+
progress: 0,
|
|
18
|
+
justFired: false
|
|
24
19
|
};
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
const elapsed = Math.min(prev.elapsed + dt, threshold);
|
|
21
|
+
const justFired = prev.elapsed < threshold && elapsed >= threshold;
|
|
27
22
|
return {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
state: {
|
|
24
|
+
elapsed,
|
|
25
|
+
armed: true
|
|
26
|
+
},
|
|
27
|
+
progress: elapsed / threshold,
|
|
28
|
+
justFired
|
|
31
29
|
};
|
|
32
|
-
}
|
|
33
|
-
const elapsed = Math.min(prev.elapsed + dt, threshold);
|
|
34
|
-
const justFired = prev.elapsed < threshold && elapsed >= threshold;
|
|
35
|
-
return {
|
|
36
|
-
state: {
|
|
37
|
-
elapsed,
|
|
38
|
-
armed: true
|
|
39
|
-
},
|
|
40
|
-
progress: elapsed / threshold,
|
|
41
|
-
justFired
|
|
42
|
-
};
|
|
43
30
|
};
|
|
44
|
-
|
|
45
31
|
export { INITIAL_HOLD_STATE, advanceHold };
|
|
@@ -1,41 +1,27 @@
|
|
|
1
|
-
/** Backing disc radius as a fraction of the button's half-size. Matches the shader's pie radius. */
|
|
2
1
|
const DISC_RADIUS = 0.92;
|
|
3
|
-
|
|
4
|
-
/** Glyph arm reach and stroke width, as fractions of the drawn size. */
|
|
5
2
|
const GLYPH_ARM = 0.24;
|
|
6
3
|
const GLYPH_WIDTH = 0.09;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
ctx.strokeStyle = '#00ff00';
|
|
30
|
-
ctx.lineWidth = size * GLYPH_WIDTH;
|
|
31
|
-
ctx.lineCap = 'round';
|
|
32
|
-
ctx.beginPath();
|
|
33
|
-
ctx.moveTo(c - arm, c - arm);
|
|
34
|
-
ctx.lineTo(c + arm, c + arm);
|
|
35
|
-
ctx.moveTo(c + arm, c - arm);
|
|
36
|
-
ctx.lineTo(c - arm, c + arm);
|
|
37
|
-
ctx.stroke();
|
|
38
|
-
ctx.restore();
|
|
4
|
+
const drawExitButtonMask = (ctx, size)=>{
|
|
5
|
+
const c = size / 2;
|
|
6
|
+
ctx.save();
|
|
7
|
+
ctx.globalCompositeOperation = 'source-over';
|
|
8
|
+
ctx.fillStyle = '#000000';
|
|
9
|
+
ctx.fillRect(0, 0, size, size);
|
|
10
|
+
ctx.globalCompositeOperation = 'lighter';
|
|
11
|
+
ctx.fillStyle = '#ff0000';
|
|
12
|
+
ctx.beginPath();
|
|
13
|
+
ctx.arc(c, c, c * DISC_RADIUS, 0, 2 * Math.PI);
|
|
14
|
+
ctx.fill();
|
|
15
|
+
const arm = size * GLYPH_ARM;
|
|
16
|
+
ctx.strokeStyle = '#00ff00';
|
|
17
|
+
ctx.lineWidth = size * GLYPH_WIDTH;
|
|
18
|
+
ctx.lineCap = 'round';
|
|
19
|
+
ctx.beginPath();
|
|
20
|
+
ctx.moveTo(c - arm, c - arm);
|
|
21
|
+
ctx.lineTo(c + arm, c + arm);
|
|
22
|
+
ctx.moveTo(c + arm, c - arm);
|
|
23
|
+
ctx.lineTo(c - arm, c + arm);
|
|
24
|
+
ctx.stroke();
|
|
25
|
+
ctx.restore();
|
|
39
26
|
};
|
|
40
|
-
|
|
41
27
|
export { drawExitButtonMask };
|