Single Selection for Brushing and Linking
Basic example of one approach to enabling hover highlighting and linking with other charts.
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/cars.json' assert {type: 'json'};
//create and export a function that takes a babylon engine and returns a scene
export const brushingLinkingSingle = function(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, 0), scene);
camera.position = new BABYLON.Vector3(0, 0.5, -5);
camera.wheelPrecision = 20;
camera.minZ = 0;
camera.attachControl(true);
//Create a scatter plot and put it on the left
let scaleX1 = d3.scaleLinear().domain(d3.extent(d3.map(data, (d) => d.Miles_per_Gallon))).range([-1,1]).nice();
let scaleY1 = d3.scaleLinear().domain(d3.extent(d3.map(data, (d) => d.Weight_in_lbs))).range([-1,1]).nice();
let scaleZ1 = d3.scaleLinear().domain(d3.extent(d3.map(data, (d) => d.Acceleration))).range([-1,1]).nice();
let scaleC = d3.scaleOrdinal(anu.ordinalChromatic('d310').toStandardMaterial());
let CoT1 = anu.create('cot', 'cot1');
let chart1 = anu.selectName('cot1', scene);
let spheres1 = chart1.bind('sphere', { diameter: 0.075 }, data)
.position((d) => new BABYLON.Vector3(scaleX1(d.Miles_per_Gallon), scaleY1(d.Weight_in_lbs), scaleZ1(d.Acceleration)))
.material((d) => scaleC(d.Origin));
anu.createAxes('myAxes1', { scale: { x: scaleX1, y: scaleY1, z: scaleZ1 }, parent: chart1 });
chart1.position(new BABYLON.Vector3(-1.25, 0, 0));
//Create a scatter plot and put it on the right
let scaleX2 = d3.scaleLinear().domain(d3.extent(d3.map(data, (d) => d.Cylinders))).range([-1,1]).nice();
let scaleY2 = d3.scaleLinear().domain(d3.extent(d3.map(data, (d) => d.Displacement))).range([-1,1]).nice();
let scaleZ2 = d3.scaleLinear().domain(d3.extent(d3.map(data, (d) => d.Horsepower))).range([-1,1]).nice();
let CoT2 = anu.create('cot', 'cot2');
let chart2 = anu.selectName('cot2', scene);
let spheres2 = chart2.bind('sphere', { diameter: 0.075 }, data)
.position((d) => new BABYLON.Vector3(scaleX2(d.Cylinders), scaleY2(d.Displacement), scaleZ2(d.Horsepower)))
.material((d) => scaleC(d.Origin));
anu.createAxes('myAxes2', { scale: { x: scaleX2, y: scaleY2, z: scaleZ2 }, parent: chart2 });
chart2.position(new BABYLON.Vector3(1.5, 0, 0));
//Make a new selection with all the spheres so that we only need to call .action() once to affect both scatter plots
let allSpheres = anu.selectName('sphere', scene)
.action((d,n,i) => new BABYLON.ExecuteCodeAction( //When the pointer over event happens, select all meshes with bound data
BABYLON.ActionManager.OnPointerOverTrigger, //that matches this mesh, then set their render outline and scaling
() => {
anu.selectData(Object.keys(d), Object.values(d), scene, true)
.prop('renderOutline', true)
.scaling(new BABYLON.Vector3(1.5, 1.5, 1.5));
}
))
.action((d,n,i) => new BABYLON.ExecuteCodeAction( //When the pointer out event happens, select all meshes with bound data
BABYLON.ActionManager.OnPointerOutTrigger, //that matches this mesh, then reset their render outline and scaling
() => {
anu.selectData(Object.keys(d), Object.values(d), scene, true)
.prop('renderOutline', false)
.scaling(BABYLON.Vector3.One());
}
));
return scene;
};