diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/graph.js | 110 | ||||
| -rw-r--r-- | src/views/Legend.js | 12 |
2 files changed, 76 insertions, 46 deletions
diff --git a/src/graph.js b/src/graph.js index 84d9d79..ffba2c2 100644 --- a/src/graph.js +++ b/src/graph.js @@ -3,12 +3,17 @@ import ForceGraph3D from "3d-force-graph"; import SpriteText from "three-spritetext"; import { union } from "./utils/set_utils.js"; import { randint, choice, pad } from "./utils/index.js"; +import { addSkyGradient } from "./sky.js"; const IMG_SCALE = 16; -const MAIN_IMG_SCALE = 80; +const MAIN_IMG_SCALE = 100; const PAINTING_SCALE = 30; const VIDEO_SCALE = 40; const OBJECT_SCALE = 10; +const OBJECT_SCALES = { + 39: 20, + 31: 20, +}; const PAINTINGS = new Set([2, 10, 21, 22, 23, 24, 27, 40, 42]); @@ -22,7 +27,6 @@ export default function buildGraph({ db, handlers }) { /** * load nodes and links */ - db.page.forEach((item, index) => { const node = { title: item.short_title, @@ -81,27 +85,44 @@ export default function buildGraph({ db, handlers }) { const highlightNodes = new Set(); const highlightLinks = new Set(); let selectedNode = null; - const objects = []; + let objects = []; /** build group */ - let graph = ForceGraph3D(); + let graph = ForceGraph3D({ controlType: "orbit" }); graph(document.querySelector("#graph")) .graphData(data) .showNavInfo(false) .nodeLabel((node) => node.title) .nodeThreeObject((node) => { let sprite, material, texture, video; + let catNumber = node.id + 1; + // if (catNumber !== 48) return null; + // 3D object if (node.data.object) { - objects.push({ id: node.id, object: node.data.object }); - const object = node.data.object; + const object = node.data.object.clone(); + const objectHandle = { catNumber, object }; + objects.push(objectHandle); var box = new THREE.Box3().setFromObject(object); var center = new THREE.Vector3(); box.getCenter(center); object.position.sub(center); - object.scale.set(OBJECT_SCALE, OBJECT_SCALE, OBJECT_SCALE); + if (OBJECT_SCALES[catNumber]) { + object.scale.set( + OBJECT_SCALES[catNumber], + OBJECT_SCALES[catNumber], + OBJECT_SCALES[catNumber] + ); + } else { + object.scale.set(OBJECT_SCALE, OBJECT_SCALE, OBJECT_SCALE); + } + const quaternion = graph.camera().quaternion; + reorientObject(quaternion)(objectHandle); return object; - } else if (node.data.thumbnail?.uri) { + } + // Videos and images + else if (node.data.thumbnail?.uri) { + // Video thumbs const isVideo = node.data.thumbnail.type === "video"; if (isVideo) { video = document.createElement("video"); @@ -111,24 +132,34 @@ export default function buildGraph({ db, handlers }) { video.autoplay = true; video.play(); texture = new THREE.VideoTexture(video); - } else { + } + // Image thumbs + else { texture = new THREE.TextureLoader().load(node.data.thumbnail.uri); } - // console.log(imgTexture); const aspect = node.data.thumbnail.width / node.data.thumbnail.height; material = new THREE.SpriteMaterial({ map: texture }); sprite = new THREE.Sprite(material); + // First image if (node.id === 0) { sprite.scale.set(MAIN_IMG_SCALE, MAIN_IMG_SCALE / aspect); - } else if (PAINTINGS.has(node.id + 1)) { + } + // Paintings + else if (PAINTINGS.has(catNumber)) { sprite.scale.set(PAINTING_SCALE, PAINTING_SCALE / aspect); - } else if (isVideo) { + } + // Videos + else if (isVideo) { sprite.scale.set(VIDEO_SCALE, VIDEO_SCALE / aspect); - } else { + } + // Other images + else { sprite.scale.set(IMG_SCALE, IMG_SCALE / aspect); } return sprite; - } else { + } + // Texts + else { sprite = new SpriteText( node.title.split(/[ :]+/).slice(0, 3).join(" ") ); @@ -154,19 +185,31 @@ export default function buildGraph({ db, handlers }) { handlers.click(node); }) - .linkWidth((link) => (highlightLinks.has(link) ? 4 : 1)); + .linkWidth((link) => (highlightLinks.has(link) ? 2 : 0.75)); - graph.controls().addEventListener("change", () => { + // graph.backgroundColor("#000000"); + // graph.renderer().setClearColor(0x000000, 0); + addSkyGradient(graph.scene()); + + const reorient = () => { const quaternion = graph.camera().quaternion; - const { axis, angle } = getAxisAndAngelFromQuaternion(quaternion); - objects.forEach(({ id, object }) => { - object.setRotationFromQuaternion(quaternion); - // the clock object is turned 90 degrees - if (id === 32) { - object.rotateY(Math.PI / 2); - } - }); - }); + objects.forEach(reorientObject(quaternion)); + }; + + const reorientObject = (quaternion) => ({ catNumber, object }) => { + object.setRotationFromQuaternion(quaternion); + // the clock object is turned 90 degrees + if (catNumber === 33) { + object.rotateY(Math.PI / 2); + } + if (catNumber === 48) { + object.rotateZ(Math.PI * -0.25); + object.rotateX(Math.PI * -0.45); + object.rotateY(Math.PI * 0.5); + } + }; + + graph.controls().addEventListener("change", reorient); const updateHighlight = () => { // trigger update of highlighted objects in scene @@ -221,6 +264,7 @@ export default function buildGraph({ db, handlers }) { } const { nodes, links } = data; const visible = new Set(); + objects = []; const selectedData = {}; selectedData.nodes = nodes.filter((node) => { @@ -243,7 +287,7 @@ export default function buildGraph({ db, handlers }) { zoomIn(); }; - // graph.d3Force("charge").strength(-150); + graph.d3Force("charge").strength(-100); // camera orbit initialZoom(); @@ -254,18 +298,4 @@ export default function buildGraph({ db, handlers }) { // stars(); } -function getAxisAndAngelFromQuaternion(q) { - const angle = 2 * Math.acos(q.w); - var s; - if (1 - q.w * q.w < 0.000001) { - // test to avoid divide by zero, s is always positive due to sqrt - // if s close to zero then direction of axis not important - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/ - s = 1; - } else { - s = Math.sqrt(1 - q.w * q.w); - } - return { axis: new THREE.Vector3(q.x / s, q.y / s, q.z / s), angle }; -} - const commonGroups = (a, b) => union(a.groups, b.groups); diff --git a/src/views/Legend.js b/src/views/Legend.js index 411ca81..eac860c 100644 --- a/src/views/Legend.js +++ b/src/views/Legend.js @@ -7,16 +7,16 @@ import React, { useState, useEffect } from "react"; var categories = [ // tag ID = array offset + 1 "1620s", - "painting", - "blunt", + "Painting", + "Blunt", "National Gallery of Canada", "Art Gallery of Ontario", "Courtauld Institute", "Stankievech", - "connsoeurship", - "double agent", - "forensics", - "black box", + "Connosieurship", + "Double Agent", + "Forensics", + "Black Box", ]; export default function Legend({ visible, selected, onSelect }) { |
