Transform Widget UI
Overview
The Transform Widget UI prefab allows you to quickly attach 3D UI widgets for manipulating position, rotation, and scale to elements in a selection. These prefabs use pointer down and out events and pointer behaviors to perform the interaction. The Mesh based UI and behavior can be customized through the method options, or after creation via selection. We use pointer based interactions as it better supports multiple platforms and one handed interaction for better accessability. These methods are members of the Selection class and will create a UI for each node in a selection. As such, it is recommended to call the prefab functions from root node selections.
Usage
js
let root = anu.bind("cot") //Returns a selection of the single root transform node
root.positionUI(options?: {})
.rotateUI(options?: {})
.scaleUI(options?: {})
Options
Position Widget UI
Property | Value | Default |
---|---|---|
name | (string) name prefix for UI and UI parent | node.name + "PositionUI" |
width | (number) the width of the capsule mesh | half the width of the parent node bounding box |
radius | (number) the radius of the capsule mesh | 5% the width |
position | (Vector3) the starting position of the capsule mesh | bottom front position of the parent node bounding box |
offset | (Vector3) the offset from the starting position | 2.5 times the radius -y axis |
material | (Material) the material of the capsule mesh | StandardMaterial |
diffuseColor | (Color3 | Color4) the diffuse color of the material if not defined |
visibility | (number) the visibility of the capsule 0-1 | 1 |
behavior | (SixDofDragBehavior) the behavior attached to the parent node | SixDofDragBehavior forceCameraOnDragStart=true rotateAroundYOnly=true |
billboard | (number) the billboard mode setting for the parent mesh | 0 |
Rotation Widget UI
Property | Value | Default |
---|---|---|
name | (string) name prefix for UI and UI parent | node.name + "RotationUI" |
axis | ({x | y |
diameter | (number) the diameter of the torus mesh | 5% the width of the parent node bounding box |
thickness | (number) the thickness of the torus mesh | half the diameter |
position | (Vector3) the starting position of the capsule mesh | bottom front position of the parent node bounding box |
offset | (Vector3) the offset from the starting position | 2.5 times the radius + 2.5 times the diameter -y axis |
material | (Material) the material of the torus mesh | StandardMaterial |
diffuseColor | (Color3 | Color4) the diffuse color of the material if not defined |
visibility | (number) the visibility of the torus 0-1 | 1 |
billboard | (number) the billboard mode setting for the parent mesh | 0 |
Scale Widget UI
Property | Value | Default |
---|---|---|
name | (string) name prefix for UI and UI parent | node.name + "ScaleUI" |
diameter | (number) the radius of the sphere mesh | 5% the width of the parent bounding box |
position | (Vector3) the starting position of the sphere mesh | bottom front position of the parent node bounding box |
offset | (Vector3) the offset from the starting position | 2.5 times the radius -y axis and the width of the hypothetical positionUI z axis |
material | (Material) the material of the sphere mesh | StandardMaterial |
diffuseColor | (Color3 | Color4) the diffuse color of the material if not defined |
visibility | (number) the visibility of the sphere 0-1 | 1 |
behavior | (PointerDragBehavior) the behavior attached to the parent node | PointerDragBehavior dragAxis (0,1,0) moveAttached=false |
billboard | (number) the billboard mode setting for the parent mesh | 0 |
minimum | (number) minimum scale factor | infinity |
maximum | (number) maximum scale factor | infinity |
Examples
js
// SPDX-License-Identifier: Apache-2.0
// Copyright : J.P. Morgan Chase & Co.
import * as anu from '@jpmorganchase/anu';
import * as BABYLON from '@babylonjs/core';
import * as d3 from 'd3';
import data from './data/iris.json' assert {type: 'json'};
export function transformWidget(engine) {
//Create an empty Scene
const scene = new BABYLON.Scene(engine);
//Add some lighting
new BABYLON.HemisphericLight('light1', new BABYLON.Vector3(0, 10, 0), scene);
//Add a camera that rotates around the origin and adjust its properties
const camera = new BABYLON.ArcRotateCamera('Camera', 0, 0, 0, new BABYLON.Vector3(0, -0.25, 0), scene);
camera.position = new BABYLON.Vector3(2, 1.5, -4);
camera.wheelPrecision = 20;
camera.minZ = 0;
camera.attachControl(true);
//Create the D3 functions that we will use to scale our data dimensions to desired output ranges for our visualization
let scaleX = d3.scaleLinear().domain(d3.extent(d3.map(data, (d) => d.sepalLength))).range([-1,1]).nice();
let scaleY = d3.scaleLinear().domain(d3.extent(d3.map(data, (d) => d.petalLength))).range([-1,1]).nice();
let scaleZ = d3.scaleLinear().domain(d3.extent(d3.map(data, (d) => d.sepalWidth))).range([-1,1]).nice();
//Do the same for color, using Anu helper functions to map values to StandardMaterial objects with colors based on the 'schemecategory10' palette from D3
let scaleC = d3.scaleOrdinal(anu.ordinalChromatic('d310').toStandardMaterial());
//Create a Center of Transform TransformNode that serves the parent node for all our meshes that make up our chart
let CoT = anu.create('cot', 'cot');
//Select our CoT so that we have it as a Selection object
let chart = anu.selectName('cot', scene);
//Create sphere meshes as children of our CoT for each row of our data and set their visual encodings using method chaining
let spheres = chart.bind('sphere', { diameter: 0.05 }, data)
.position((d) => new BABYLON.Vector3(scaleX(d.sepalLength), scaleY(d.petalLength), scaleZ(d.sepalWidth)))
.material((d) => scaleC(d.species));
//Use the Axes prefab with our three D3 scales
anu.createAxes('myAxes', { scale: { x: scaleX, y: scaleY, z: scaleZ }, parent: chart });
//Use the Transform Widget prefab to add 3D UI handles to position, rotate, and scale our chart
chart.positionUI()
.rotateUI()
.scaleUI({ minimum: 0.5, maximum: 2 });
return scene;
};