Pointer Hover
Example demonstrating how to use the .action() method to add Babylon pointer actions to nodes in a selection.
js
// SPDX-License-Identifier: Apache-2.0
// Copyright : J.P. Morgan Chase & Co.
import * as anu from '@jpmorganchase/anu';
import * as d3 from "d3";
import { Scene, HemisphericLight, ArcRotateCamera, Vector3, Color3, ActionManager, InterpolateValueAction, ExecuteCodeAction, HighlightLayer } from '@babylonjs/core';
import penguins from './data/penguins.json' assert {type: 'json'}; //Our data
//Create and export a function that takes a Babylon engine and returns a Babylon Scene
export function hover(engine) {
//Create an empty Scene
const scene = new Scene(engine);
//Add some lighting
new HemisphericLight('light1', new Vector3(0, 10, 0), scene);
//Add a camera that rotates around the origin and adjust its properties
const camera = new ArcRotateCamera("Camera", -(Math.PI / 4) * 3, Math.PI / 4, 10, new Vector3(0, 0, 0), scene);
camera.wheelPrecision = 20; // Adjust the sensitivity of the mouse wheel's zooming
camera.minZ = 0; // Adjust the distance of the camera's near plane
camera.attachControl(true); // Allow the camera to respond to user controls
camera.position = new Vector3(2, 2, -3.5);
//Create the D3 scale functions for the x, y, and z positions and color
let scaleX = d3.scaleLinear().domain(d3.extent(d3.map(penguins, (d) => { return d['Beak Depth (mm)'] }))).range([-1, 1]).nice();
let scaleY = d3.scaleLinear().domain(d3.extent(d3.map(penguins, (d) => { return d['Beak Length (mm)'] }))).range([-1, 1]).nice();
let scaleZ = d3.scaleLinear().domain(d3.extent(d3.map(penguins, (d) => { return d['Flipper Length (mm)'] }))).range([-1, 1]).nice();
let scaleC = d3.scaleOrdinal(anu.ordinalChromatic('d310').toStandardMaterial());
//Create a Center of Transform TransformNode using create() that serves the parent node for all our meshes that make up our chart
let CoT = anu.create("cot", "cot");
//We need to make an Anu Selection separately, as create() does not return a Section but the created Babylon TransformNode
let chart = anu.selectName("cot", scene);
//Create a Babylon HighlightLayer that will allow us to add a highlight stencil to meshes
const highlighter = new HighlightLayer("highlighter", scene);
//Create our spheres and add Actions to allow them to respond to user input
let spheres = chart.bind('sphere', { diameter: 0.05 }, penguins)
.position((d) => new Vector3(scaleX(d['Beak Depth (mm)']), scaleY(d['Beak Length (mm)']), scaleZ(d['Flipper Length (mm)'])))
.material((d) => scaleC(d.Species))
//Add an action that will increase the size of the sphere when the pointer is moved over it
.action((d, n, i) => new InterpolateValueAction( //Type of action, InterpolateValueAction will interpolave a given property's value over a specified period of time
ActionManager.OnPointerOverTrigger, //Action Trigger
n, //The Mesh or Node to Change, n in Anu refers to the mesh itself
'scaling', //The property to Change
new Vector3(1.2, 1.2, 1.2), //The value that the property should be set to
100 //The duration in milliseconds that the value is interpolated for
))
//Add an action that will return the size of the sphere to its original value when the pointer is moved out of it
.action((d, n, i) => new InterpolateValueAction(
ActionManager.OnPointerOutTrigger,
n,
'scaling',
new Vector3(1, 1, 1),
100
))
//Add an action that will highlight the sphere mesh using the highlight stencil when the pointer is moved over it
.action((d,n,i) => new ExecuteCodeAction( //ExecudeCodeAction allows us to execute a given function
ActionManager.OnPointerOverTrigger,
() => {
highlighter.addMesh(n, Color3.White());
}
))
//Add an action that will remove the highlight on the sphere mesh when the pointer is moved out of it
.action((d,n,i) => new ExecuteCodeAction( //Same as above but in reverse
ActionManager.OnPointerOutTrigger,
() => {
highlighter.removeMesh(n);
}
))
//Use the createAxes() Anu helper function to create the axes for us based on our D3 scale functions
anu.createAxes('test', scene, { parent: chart, scale: { x: scaleX, y: scaleY, z: scaleZ }, labelOptions: {size: 0.02} });
return scene;
};