From 0ada3fce6fb9f478dda687d42de6962364f10970 Mon Sep 17 00:00:00 2001 From: Mike Lynch Date: Fri, 26 Apr 2024 18:31:27 +1000 Subject: [PATCH] A few more ux refinements, and added the ability to hide captions --- fourDShape.js | 36 ++++++++++-------------------------- gui.js | 33 +++++++++++++++++++++------------ main.js | 31 ++++++++++++++++++++++++++++--- 3 files changed, 59 insertions(+), 41 deletions(-) diff --git a/fourDShape.js b/fourDShape.js index 35e6c0e..888ebd7 100644 --- a/fourDShape.js +++ b/fourDShape.js @@ -2,7 +2,7 @@ import * as THREE from 'three'; const HYPERPLANE = 2.0; -const W_FORESHORTENING = 0.4; +const W_FORESHORTENING = 0.04; class FourDShape extends THREE.Group { @@ -50,7 +50,10 @@ class FourDShape extends THREE.Group { const length = n1.v3.distanceTo(n2.v3); const centre = new THREE.Vector3(); centre.lerpVectors(n1.v3, n2.v3, 0.5); - const geometry = new THREE.CylinderGeometry(this.link_scale * s2, this.link_scale * s1, 1); + const geometry = new THREE.CylinderGeometry( + this.link_scale * s2, this.link_scale * s1, 1, + 16, 1, true + ); const cyl = new THREE.Mesh(geometry, material); const edge = new THREE.Group(); edge.add(cyl); @@ -70,36 +73,17 @@ class FourDShape extends THREE.Group { const length = n1.v3.distanceTo(n2.v3); const centre = new THREE.Vector3(); centre.lerpVectors(n1.v3, n2.v3, 0.5); - // is this really the only way to do this? - //const geometry = new THREE.CylinderGeometry(this.link_scale * s2, this.link_scale * s1, 1); - //link.object.children[0].geometry.dispose(); - this.forshortenLink(link.object.children[0].geometry, this.link_scale * s2, this.link_scale * s1); - //const link_hack = this.link_scale * (s1 + s2) * 0.5; - link.object.scale.copy(new THREE.Vector3(1, 1, length)); + // take the average of the ends as the thickness - as a workaround, + // because I haven't worked out how to reshape tapered links without + // having to reassign a new geometry to every link + const link_mean = this.link_scale * (s1 + s2) * 0.5; + link.object.scale.copy(new THREE.Vector3(link_mean, link_mean, length)); link.object.position.copy(centre); link.object.lookAt(n2.v3); link.object.children[0].rotation.x = Math.PI / 2.0; - // link.object.children[0].geometry.needsUpdate = true; - // link.object.children[0].geometry.computeVertexNormals(); link.object.visible = (!links_show || link.label in links_show); } - forshortenLink(geometry, top, bottom) { - const count = geometry.attributes.position.count; - for( let i = 0; i < count; i++ ) { - const x = geometry.attributes.position.getX(i); - const y = geometry.attributes.position.getY(i); - const z = geometry.attributes.position.getZ(i); - if( z == 0 ) { - geometry.attributes.position.setX(i, x * top); - geometry.attributes.position.setY(i, y * top); - } else { - geometry.attributes.position.setX(i, x * bottom); - geometry.attributes.position.setY(i, y * bottom); - } - } - } - setFaceGeometry(face, geometry) { const values = []; diff --git a/gui.js b/gui.js index db46041..baba2ea 100644 --- a/gui.js +++ b/gui.js @@ -2,10 +2,11 @@ import { GUI } from 'lil-gui'; const DEFAULTS = { - thickness: 0.02, - nodesize: 0.02, - linkopacity: 0.5, - link2opacity: 0.5, + nodesize: 0.25, + nodeopacity: 1, + linksize: 0.2, + linkopacity: 0.75, + link2opacity: 0.75, shape: '120-cell', option: 'none', visibility: 5, @@ -18,6 +19,8 @@ const DEFAULTS = { xRotate: 'YW', yRotate: 'XW', dtheta: 0, + damping: false, + captions: true, dpsi: 0, } @@ -25,7 +28,7 @@ const DEFAULTS = { class FourDGUI { - constructor(shapes, changeShape, setColor, setBackground, setLinkOpacity, setVisibility) { + constructor(shapes, changeShape, setColor, setBackground, setNodeOpacity,setLinkOpacity, setVisibility, showDocs) { this.gui = new GUI(); const SHAPE_NAMES = shapes.map((s) => s.name); @@ -36,10 +39,11 @@ class FourDGUI { option: this.link['option'], inscribed: this.link['inscribed'], inscribe_all: this.link['inscribe_all'], - thickness: this.link['thickness'], + linksize: this.link['linksize'], linkopacity: this.link['linkopacity'], link2opacity: this.link['linkopacity'], nodesize: this.link['nodesize'], + nodeopacity: this.link['nodeopacity'], depth: this.link['depth'], color: this.link['color'], background: this.link['background'], @@ -48,6 +52,7 @@ class FourDGUI { xRotate: this.link['xRotate'], yRotate: this.link['yRotate'], damping: false, + captions: true, dtheta: this.link['dtheta'], dpsi: this.link['dpsi'], "copy link": function () { guiObj.copyUrl() } @@ -67,18 +72,20 @@ class FourDGUI { }); this.gui.add(this.params, 'hyperplane', 0.5, 1 / 0.8); this.gui.add(this.params, 'zoom', 0.1, 2.0); - this.gui.add(this.params, 'thickness', 0, 0.1); + this.gui.add(this.params, 'nodesize', 0, 1); + this.gui.add(this.params, 'nodeopacity', 0, 1).onChange(setNodeOpacity); + this.gui.add(this.params, 'linksize', 0, 1); this.gui.add(this.params, 'linkopacity', 0, 1).onChange( (v) => setLinkOpacity(v, true) ); this.gui.add(this.params, 'link2opacity', 0, 1).onChange( (v) => setLinkOpacity(v, false) ); - this.gui.add(this.params, 'nodesize', 0, 0.1); this.gui.addColor(this.params, 'color').onChange(setColor); this.gui.addColor(this.params, 'background').onChange(setBackground); this.gui.add(this.params, 'xRotate', [ 'YW', 'YZ', 'ZW' ]); this.gui.add(this.params, 'yRotate', [ 'XZ', 'XY', 'XW' ]); + this.gui.add(this.params, 'captions').onChange(showDocs); this.gui.add(this.params, 'damping'); this.gui.add(this.params, 'copy link'); @@ -134,10 +141,11 @@ class FourDGUI { } this.link['hyperplane'] = this.numParam('hyperplane', parseFloat); this.link['zoom'] = this.numParam('zoom', parseFloat); - this.link['thickness'] = this.numParam('thickness', parseFloat); + this.link['linksize'] = this.numParam('linksize', parseFloat); this.link['linkopacity'] = this.numParam('linkopacity', parseFloat); this.link['link2opacity'] = this.numParam('link2opacity', parseFloat); this.link['nodesize'] = this.numParam('nodesize', parseFloat); + this.link['nodeopacity'] = this.numParam('nodeopacity', parseFloat); this.link['color'] = this.numParam('color', (s) => guiObj.stringToHex(s)); this.link['background'] = this.numParam('background', (s) => guiObj.stringToHex(s)); this.link['dpsi'] = this.numParam('dpsi', parseFloat); @@ -151,10 +159,11 @@ class FourDGUI { url.searchParams.append("option", this.params.option); url.searchParams.append("inscribed", this.params.inscribed ? 'y': 'n'); url.searchParams.append("inscribe_all", this.params.inscribe_all ? 'y': 'n'); - url.searchParams.append("thickness", this.params.thickness.toString()); + url.searchParams.append("linksize", this.params.linksize.toString()); url.searchParams.append("nodesize", this.params.nodesize.toString()); - url.searchParams.append("linkopacity", this.params.thickness.toString()); - url.searchParams.append("link2opacity", this.params.nodesize.toString()); + url.searchParams.append("nodeopacity", this.params.nodesize.toString()); + url.searchParams.append("linkopacity", this.params.nodeopacity.toString()); + url.searchParams.append("link2opacity", this.params.link2opacity.toString()); url.searchParams.append("color", this.hexToString(this.params.color)); url.searchParams.append("background", this.hexToString(this.params.background)); url.searchParams.append("hyperplane", this.params.hyperplane.toString()); diff --git a/main.js b/main.js index 5045917..04d8497 100644 --- a/main.js +++ b/main.js @@ -47,11 +47,19 @@ material.opacity = 0.5; const node_ms = node_colours.map((c) => new THREE.MeshStandardMaterial({color: c})); const link_ms = node_colours.map((c) => new THREE.MeshStandardMaterial({color: c})); +node_ms.map((m) => { + m.transparent = true; + m.opacity = 1.0; + } +); + link_ms.map((m) => { m.transparent = true; m.opacity = 0.5; } -) +); + + const face_ms = [ new THREE.MeshLambertMaterial( { color: 0x44ff44 } ) @@ -95,6 +103,16 @@ function displayDocs(name) { } } +function showDocs(visible) { + console.log(`showDocs ${visible}`); + const docdiv = document.getElementById("description"); + if( visible ) { + docdiv.style.display = ''; + } else { + docdiv.style.display = 'none'; + } +} + // initialise gui and read params from URL // callbacks to do things which are triggered by controls: reset the shape, @@ -125,6 +143,11 @@ function setLinkOpacity(o, primary) { } } +function setNodeOpacity(o) { + node_ms.map((nm) => nm.opacity = o); +} + + let gui; @@ -149,8 +172,10 @@ gui = new FourDGUI( changeShape, setColors, setBackground, + setNodeOpacity, setLinkOpacity, - setVisibility + setVisibility, + showDocs ); // these are here to pick up colour settings from the URL params @@ -216,8 +241,8 @@ function animate() { shape.hyperplane = 1 / gui.params.hyperplane; camera.position.set(0, 0, gui.params.zoom * CAMERA_K * gui.params.hyperplane); - shape.link_scale = gui.params.thickness; shape.node_scale = gui.params.nodesize; + shape.link_scale = gui.params.linksize * gui.params.nodesize * 0.5; shape.render3(rotations, node_show, link_show);