diff options
| author | Jules Laplace <julescarbon@gmail.com> | 2021-09-21 15:24:38 +0200 |
|---|---|---|
| committer | Jules Laplace <julescarbon@gmail.com> | 2021-09-21 15:24:38 +0200 |
| commit | 48374c440e344745ecbf96a3e2803fdc2bf35626 (patch) | |
| tree | 83351e625743b31e5d13d797b8687742637457ea | |
| parent | b08b596b34a9f84248df294c7ee4f0c953e000a2 (diff) | |
font and sky and such
| -rw-r--r-- | data_store/tags.csv | 2 | ||||
| -rw-r--r-- | db.json | 34 | ||||
| -rw-r--r-- | load_spreadsheet.js | 3 | ||||
| -rw-r--r-- | public/assets/css/css.css | 19 | ||||
| -rw-r--r-- | public/assets/css/fonts.css | 8 | ||||
| -rw-r--r-- | src/graph.js | 110 | ||||
| -rw-r--r-- | src/views/Legend.js | 12 |
7 files changed, 108 insertions, 80 deletions
diff --git a/data_store/tags.csv b/data_store/tags.csv index 4732384..1a2874b 100644 --- a/data_store/tags.csv +++ b/data_store/tags.csv @@ -1,4 +1,4 @@ -Title,,1620s,painting,blunt,National Gallery of Canada,Art Gallery of Ontario,Courtauld Institute,Stankievech,connsoeurship,double agent,forensics ,black box,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+Title,,1620s,painting,blunt,National Gallery of Canada,Art Gallery of Ontario,Courtauld Institute,Stankievech,connsoeurship,double agent,forensics,black box,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
01 Poussin: No6092,1,x,x,x,x,,,,x,,x,x,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
02 No6092: Xray,2,,,,x,,,,,,x,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
03 Blunt: Apollo,3,,,x,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
@@ -11,8 +11,8 @@ "tag_2": 3, "tag_3": 4, "tag_4": 8, - "tag_5": 11, - "tag_6": 0, + "tag_5": 10, + "tag_6": 11, "tag_7": 0, "tag_8": 0, "images": [ @@ -42,7 +42,7 @@ "short_title": "02 No6092: Xray", "type": "image", "tag_0": 4, - "tag_1": 0, + "tag_1": 10, "tag_2": 0, "tag_3": 0, "tag_4": 0, @@ -210,7 +210,7 @@ "short_title": "06 NGC: Record ", "type": "image", "tag_0": 4, - "tag_1": 0, + "tag_1": 10, "tag_2": 0, "tag_3": 0, "tag_4": 0, @@ -364,7 +364,7 @@ "short_title": "10 No6092: Label ", "type": "image", "tag_0": 4, - "tag_1": 0, + "tag_1": 10, "tag_2": 0, "tag_3": 0, "tag_4": 0, @@ -749,7 +749,7 @@ "short_title": "20 Rees: Xrays", "type": "image", "tag_0": 6, - "tag_1": 0, + "tag_1": 10, "tag_2": 0, "tag_3": 0, "tag_4": 0, @@ -806,7 +806,7 @@ "type": "image", "tag_0": 2, "tag_1": 4, - "tag_2": 0, + "tag_2": 10, "tag_3": 0, "tag_4": 0, "tag_5": 0, @@ -929,7 +929,7 @@ "short_title": "25 Chu: Courbet Signature", "type": "image", "tag_0": 5, - "tag_1": 0, + "tag_1": 10, "tag_2": 0, "tag_3": 0, "tag_4": 0, @@ -964,7 +964,7 @@ "short_title": "26 Fernier: Courbet Signatures", "type": "image", "tag_0": 5, - "tag_1": 0, + "tag_1": 10, "tag_2": 0, "tag_3": 0, "tag_4": 0, @@ -999,7 +999,7 @@ "short_title": "27 Courbet: Signature", "type": "image", "tag_0": 5, - "tag_1": 0, + "tag_1": 10, "tag_2": 0, "tag_3": 0, "tag_4": 0, @@ -1449,7 +1449,7 @@ "tag_0": 6, "tag_1": 8, "tag_2": 9, - "tag_3": 0, + "tag_3": 10, "tag_4": 0, "tag_5": 0, "tag_6": 0, @@ -1485,7 +1485,7 @@ "tag_1": 2, "tag_2": 8, "tag_3": 9, - "tag_4": 0, + "tag_4": 10, "tag_5": 0, "tag_6": 0, "tag_7": 0, @@ -1519,7 +1519,7 @@ "tag_0": 1, "tag_1": 7, "tag_2": 8, - "tag_3": 0, + "tag_3": 10, "tag_4": 0, "tag_5": 0, "tag_6": 0, @@ -1594,8 +1594,8 @@ "short_title": "44 Poe: Purloined Letter", "type": "image", "tag_0": 9, - "tag_1": 11, - "tag_2": 0, + "tag_1": 10, + "tag_2": 11, "tag_3": 0, "tag_4": 0, "tag_5": 0, @@ -1792,8 +1792,8 @@ "tag_0": 3, "tag_1": 5, "tag_2": 9, - "tag_3": 11, - "tag_4": 0, + "tag_3": 10, + "tag_4": 11, "tag_5": 0, "tag_6": 0, "tag_7": 0, diff --git a/load_spreadsheet.js b/load_spreadsheet.js index acfdd35..1d4539f 100644 --- a/load_spreadsheet.js +++ b/load_spreadsheet.js @@ -60,6 +60,9 @@ async function main() { // if there is a corresponding record in the data store, accumulate it if (String(index + 1) in dataStore) { await loadFiles(dataStore[index + 1], record); + if (!record.images.length) { + console.log(`/!\\ No images: ${dataStore[index + 1]} // ${row.Title}`); + } } // if we haven't seen this ID before, append it if (!pageById[index]) { diff --git a/public/assets/css/css.css b/public/assets/css/css.css index 590e530..287dceb 100644 --- a/public/assets/css/css.css +++ b/public/assets/css/css.css @@ -6,7 +6,7 @@ body { height: 100%; overflow: hidden; background: black; - font-family: "Merriweather", serif; + font-family: "Spectral", serif; } .scene-tooltip { background: black; @@ -16,7 +16,7 @@ body { text-align: center; font-size: 1rem !important; line-height: 1.5; - font-family: "Merriweather", serif !important; + font-family: "Spectral", serif !important; } /** Legend */ @@ -25,15 +25,12 @@ body { position: absolute; bottom: 0; left: 0; - font-size: 0.75rem; + font-size: 0.875rem; line-height: 1.75; - padding: 1rem; - margin: 1rem 2rem; - background: rgba(0, 0, 0, 0.5); + margin: 1rem 1.5rem; + /*background: rgba(0, 0, 0, 0.5);*/ color: #fff; transition: opacity 0.2s; - text-transform: uppercase; - font-variant: small-caps; } .legend .category { cursor: pointer; @@ -69,7 +66,7 @@ body { pointer-events: none; transition: opacity 0.2s; opacity: 0; - background: rgba(0, 0, 0, 0.75); + background: rgba(0, 0, 0, 0.8); color: white; display: flex; flex-direction: row; @@ -85,7 +82,7 @@ body { .detail .content > div { min-height: 100%; padding: 3rem 5rem 6rem 5rem; - background: rgba(0, 0, 0, 0.5); + /*background: rgba(0, 0, 0, 0.5);*/ } .detail .media { padding: 3rem 5rem; @@ -106,8 +103,6 @@ body { font-size: 1.25rem; line-height: 1.5; margin-bottom: 2rem; - text-transform: capitalize; - font-variant: small-caps; } .detail .title .index { margin-bottom: 0.75rem; diff --git a/public/assets/css/fonts.css b/public/assets/css/fonts.css index f1e8429..a4fecb5 100644 --- a/public/assets/css/fonts.css +++ b/public/assets/css/fonts.css @@ -1,11 +1,11 @@ @font-face { - font-family: "Merriweather"; - src: url("../fonts/merriweather/Merriweather-Regular.ttf"); + font-family: "Spectral"; + src: url("../fonts/spectral/Spectral-Regular.ttf"); font-style: normal; } @font-face { - font-family: "Merriweather"; - src: url("../fonts/merriweather/Merriweather-Italic.ttf"); + font-family: "Spectral"; + src: url("../fonts/spectral/Spectral-Italic.ttf"); font-style: italic; } 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 }) { |
