From 8f385e602002b9a3e5dfb85bd5f00bda83abc6ea Mon Sep 17 00:00:00 2001 From: Jonathan LEGRAND Date: Mon, 8 Apr 2024 20:37:10 +0200 Subject: [PATCH 1/9] Update js code style. --- src/ScanList/index.js | 200 ++++----- src/ScanList/list/index.js | 24 +- src/Viewer/Carousel/index.js | 297 +++++++------ src/Viewer/Interactors/Tools/index.js | 2 +- src/Viewer/Interactors/icons/index.js | 2 +- src/Viewer/Interactors/layers.js | 2 +- src/Viewer/Interactors/layers.test.js | 6 +- src/Viewer/Interactors/misc.js | 321 +++++++------- src/Viewer/Interactors/tools.js | 394 +++++++++--------- src/Viewer/World/entities/aabb.js | 47 +-- src/Viewer/World/entities/pointCloud.js | 135 +++--- .../World/entities/segmentedPointCloud.js | 5 +- src/Viewer/World/entities/workspace.js | 5 +- src/Viewer/World/index.js | 13 +- src/Viewer/World/object.js | 30 +- src/flow/interactions/reducer.js | 158 +++---- src/flow/settings/reducer.js | 2 +- src/rd/UI/Slider/index.js | 60 ++- 18 files changed, 836 insertions(+), 867 deletions(-) diff --git a/src/ScanList/index.js b/src/ScanList/index.js index ec4edab..7439b7e 100644 --- a/src/ScanList/index.js +++ b/src/ScanList/index.js @@ -26,24 +26,24 @@ License along with this program. If not, see . */ -import React, { useState } from "react"; -import { omit } from "lodash"; -import { FormattedMessage } from "react-intl"; -import { Global } from "@emotion/core"; +import React, { useState } from 'react' +import { omit } from 'lodash' +import { FormattedMessage } from 'react-intl' +import { Global } from '@emotion/core' -import styled from "@emotion/styled"; +import styled from '@emotion/styled' -import { H1, H2 } from "common/styles/UI/Text/titles"; -import { green, grey } from "common/styles/colors"; +import { H1, H2 } from 'common/styles/UI/Text/titles' +import { green, grey } from 'common/styles/colors' -import { useSearchQuery, useScans, useFiltering } from "flow/scans/accessors"; +import { useSearchQuery, useScans, useFiltering } from 'flow/scans/accessors' -import Logo from "./assets/ico.logo.160x30.svg"; -import closePicto from "common/assets/ico.deselect.20x20.svg"; +import Logo from './assets/ico.logo.160x30.svg' +import closePicto from 'common/assets/ico.deselect.20x20.svg' -import Search from "./search"; -import List from "./list"; -import Sorting from "./sorting"; +import Search from './search' +import List from './list' +import Sorting from './sorting' /** * Important note : EVERYTHING here is hardcoded. @@ -64,175 +64,175 @@ import Sorting from "./sorting"; */ const Container = styled.div({ - margin: "auto", + margin: 'auto', maxWidth: 1420, - padding: "80px 60px", - height: "100%", + padding: '80px 60px', + height: '100%', color: green, - position: "relative", -}); + position: 'relative' +}) const AppHeader = styled.div({ - display: "flex", - justifyContent: "space-between", - alignItems: "center", - paddingBottom: 50, -}); + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + paddingBottom: 50 +}) const AppIntro = styled(H2)({ - display: "block", - color: green, -}); + display: 'block', + color: green +}) const TaintedFormattedMessage = styled((props) => ( - + ))({}, (props) => { return { - color: props.color, - }; -}); + color: props.color + } +}) const ClearButton = styled((props) => { return ( - - ); + ) })({ - border: "none", + border: 'none', width: 20, height: 20, - transition: "all 0.15s ease", - cursor: "pointer", - outline: "none", + transition: 'all 0.15s ease', + cursor: 'pointer', + outline: 'none', marginLeft: 7, opacity: 1, padding: 0, - "&:focus, &:hover": { - transform: "scale(1.25)", - opacity: 0.9, - }, -}); + '&:focus, &:hover': { + transform: 'scale(1.25)', + opacity: 0.9 + } +}) const ResultsTitleContainer = styled.div({ - borderBottom: "1px solid rgba(21,119,65, 0.15)", + borderBottom: '1px solid rgba(21,119,65, 0.15)', marginTop: 51, - height: 65, -}); + height: 65 +}) -function ResultsTitle({ scans = [], search, clear }) { +function ResultsTitle ({ scans = [], search, clear }) { return ( - +

{scans ? (
- {search && search !== "" && ( -
+ {search && search !== '' && ( +
- +
)}
) : ( - "" + '' )}

- ); + ) } -function Results(props) { - const [search] = useState(props.search); - const [filtering] = useFiltering(); +function Results (props) { + const [search] = useState(props.search) + const [filtering] = useFiltering() const filteringFn = (elem) => { - let test = true; + let test = true for (let key in filtering) { if (filtering[key]) { - test = test && elem[key]; + test = test && elem[key] } } - return test; - }; + return test + } - const scans = props.scans.filter(filteringFn); + const scans = props.scans.filter(filteringFn) return ( -
+
- ); + ) } -export default function() { - const [search, setSearch] = useSearchQuery(); - const [scans] = useScans(search); - +export default function () { + const [search, setSearch] = useSearchQuery() + const [scans] = useScans(search) + const elements = [ scans ? scans.length ? { - key: "scans", - element: ( - setSearch(null)} - scans={scans} - /> - ), - } + key: 'scans', + element: ( + setSearch(null)} + scans={scans} + /> + ) + } : { - key: "no-results", - element: ( - setSearch(null)} - /> - ), - } + key: 'no-results', + element: ( + setSearch(null)} + /> + ) + } : { - key: "loading", - element: "", - }, - ]; + key: 'loading', + element: '' + } + ] return ( -
+
- + - + @@ -240,8 +240,8 @@ export default function() {
-
{elements[0].element}
+
{elements[0].element}
- ); + ) } diff --git a/src/ScanList/list/index.js b/src/ScanList/list/index.js index 5056f01..d8bb394 100644 --- a/src/ScanList/list/index.js +++ b/src/ScanList/list/index.js @@ -99,7 +99,7 @@ const Name = styled.div({ lineHeight: '18px', fontWeight: 700, padding: 5, - justifyContent:'centered' + justifyContent: 'centered' }) const Options = styled.div({ @@ -177,7 +177,7 @@ const Actions = styled.div({ marginLeft: '42px' }) -const OpenButton = styled((props) => )({ +const OpenButton = styled((props) => )({ display: 'inline-block', padding: '9px 38px', fontSize: 15, @@ -188,7 +188,7 @@ const OpenButton = styled((props) => )( outline: 'none', cursor: 'pointer', textDecoration: 'none', - background:green, + background: green, '&:focus, &:hover': { textDecoration: 'underline', @@ -199,11 +199,12 @@ const OpenButton = styled((props) => )( background: darkGreen } }, (props) => { - if(props.isActiveLink) + if (props.isActiveLink) { return { pointerEvents: 'none', - background:red + background: red } + } }) const Links = styled.div({ @@ -236,16 +237,15 @@ export const DocLink = styled.a({ }) export const Item = memo(({ item }) => { - - const docLinkArchive = item.error ? void(0) : item.metadata.files.archive - const docLinkMeta = item.error ? void(0) : item.metadata.files.metadatas - const ThumbnailUri = item.error ? DatasetErrorIcon : item.thumbnailUri; // in a React component means ReactDOM will ignore such attribute + const docLinkArchive = item.error ? void (0) : item.metadata.files.archive + const docLinkMeta = item.error ? void (0) : item.metadata.files.metadatas + const ThumbnailUri = item.error ? DatasetErrorIcon : item.thumbnailUri // in a React component means ReactDOM will ignore such attribute return -
{item.metadata.plant}
- {item.id} +
{item.metadata.plant}
+ {item.id}
{item.metadata.species} {item.metadata.environment} @@ -328,7 +328,7 @@ export const Item = memo(({ item }) => { - + diff --git a/src/Viewer/Carousel/index.js b/src/Viewer/Carousel/index.js index bb49a34..69314c3 100644 --- a/src/Viewer/Carousel/index.js +++ b/src/Viewer/Carousel/index.js @@ -26,103 +26,103 @@ License along with this program. If not, see . */ -import React, { useState, useRef, useEffect, memo } from "react"; -import { useWindowSize } from "react-use"; -import styled from "@emotion/styled"; +import React, { useState, useRef, useEffect, memo } from 'react' +import { useWindowSize } from 'react-use' +import styled from '@emotion/styled' -import { scaleCanvas } from "rd/tools/canvas"; +import { scaleCanvas } from 'rd/tools/canvas' -import { useScan, useImageSet } from "flow/scans/accessors"; +import { useScan, useImageSet } from 'flow/scans/accessors' -import { green, red } from "common/styles/colors"; -import closeIco from "common/assets/ico.deselect-white.20x20.svg"; +import { green, red } from 'common/styles/colors' +import closeIco from 'common/assets/ico.deselect-white.20x20.svg' import { useHoveredCamera, - useSelectedcamera, -} from "flow/interactions/accessors"; -import { useCarousel } from "flow/settings/accessors"; -import { useFormatMessage } from "rd/tools/intl"; + useSelectedcamera +} from 'flow/interactions/accessors' +import { useCarousel } from 'flow/settings/accessors' +import { useFormatMessage } from 'rd/tools/intl' -import useImgLoader from "./loader"; -import openIco from "./assets/ico.open_photo.16x16.svg"; -import dragNdropIco from "./assets/ico.drag_photos.40x16.svg"; +import useImgLoader from './loader' +import openIco from './assets/ico.open_photo.16x16.svg' +import dragNdropIco from './assets/ico.drag_photos.40x16.svg' -export const moduleHeight = 70; +export const moduleHeight = 70 const Container = styled.div({ - width: "100%", + width: '100%', height: moduleHeight, - background: "#1f2426", - position: "relative", - zIndex: 1000, // This is to prevent the close and open buttons to conflict + background: '#1f2426', + position: 'relative', + zIndex: 1000 // This is to prevent the close and open buttons to conflict // with the graph on the right -}); +}) const Svg = styled.svg({ - width: "100%", - height: "calc(100% + 30px)", + width: '100%', + height: 'calc(100% + 30px)', marginTop: -30, left: 0, - "& g": { - cursor: "pointer", - }, -}); + '& g': { + cursor: 'pointer' + } +}) const Canvas = styled.canvas({ - width: "100%", - height: "100%", - position: "absolute", + width: '100%', + height: '100%', + position: 'absolute', top: 0, left: 0, - pointerEvents: "none", -}); + pointerEvents: 'none' +}) const SvgDnG = styled.svg({ - width: "100%", - height: "100%", - pointerEvents: "none", - position: "absolute", + width: '100%', + height: '100%', + pointerEvents: 'none', + position: 'absolute', top: 0, left: 0, zIndex: 1, - "& rect": { - pointerEvents: "all", - }, -}); + '& rect': { + pointerEvents: 'all' + } +}) const CTAWording = styled.text({ fontSize: 11, - fill: "white", - textTransform: "uppercase", - fontWeight: 600, -}); - -const getSize = (elem) => elem.getBoundingClientRect(); - -export default function Carousel() { - const canvasRef = useRef(null); - const containerRef = useRef(null); - const windowSider = useWindowSize(); - const [scan] = useScan(); - const [urlList, setUrlList] = useState([]); - const [context, setContext] = useState(null); - const [dragging, setDragging] = useState(false); - const [picturesLayout, setPicturesLayout] = useState([]); - const cameraPoses = (scan && scan.camera.poses) || []; - const [imgs] = useImgLoader(urlList); - const [hovered, setHovered] = useHoveredCamera(); - const [selected, setSelected] = useSelectedcamera(); - const large = moduleHeight * (6000 / 4000); - let sizes; - const [carousel] = useCarousel(); - - const hoveredLayout = useRef(null); - const selectedLayout = useRef(null); - - const imageSet = useImageSet(carousel.photoSet); + fill: 'white', + textTransform: 'uppercase', + fontWeight: 600 +}) + +const getSize = (elem) => elem.getBoundingClientRect() + +export default function Carousel () { + const canvasRef = useRef(null) + const containerRef = useRef(null) + const windowSider = useWindowSize() + const [scan] = useScan() + const [urlList, setUrlList] = useState([]) + const [context, setContext] = useState(null) + const [dragging, setDragging] = useState(false) + const [picturesLayout, setPicturesLayout] = useState([]) + const cameraPoses = (scan && scan.camera.poses) || [] + const [imgs] = useImgLoader(urlList) + const [hovered, setHovered] = useHoveredCamera() + const [selected, setSelected] = useSelectedcamera() + const large = moduleHeight * (6000 / 4000) + let sizes + const [carousel] = useCarousel() + + const hoveredLayout = useRef(null) + const selectedLayout = useRef(null) + + const imageSet = useImageSet(carousel.photoSet) useEffect(() => { if (imageSet) { // Portion of code to get only 'rgb' images in dataset (doesn't work) @@ -136,55 +136,55 @@ export default function Carousel() { // index++ // }) // } - setUrlList(imageSet.map((d) => d.path)); + setUrlList(imageSet.map((d) => d.path)) } - }, [imageSet]); + }, [imageSet]) useEffect(() => { - const { width, height } = getSize(containerRef.current); - const context = canvasRef.current.getContext("2d"); - scaleCanvas(canvasRef.current, context, width, height); - context.width = width; - context.height = height; - setContext(context); - }, [windowSider, containerRef.current, canvasRef.current]); + const { width, height } = getSize(containerRef.current) + const context = canvasRef.current.getContext('2d') + scaleCanvas(canvasRef.current, context, width, height) + context.width = width + context.height = height + setContext(context) + }, [windowSider, containerRef.current, canvasRef.current]) useEffect(() => { if (context) { - const { width, height } = getSize(containerRef.current); + const { width, height } = getSize(containerRef.current) sizes = { width, large, normal: width / urlList.length, block: (width - (hovered || selected ? large : 0)) / - (hovered || selected ? urlList.length - 1 : urlList.length), - }; + (hovered || selected ? urlList.length - 1 : urlList.length) + } - let last = { x: 0, width: 0, normalX: 0, normalWidth: 0 }; + let last = { x: 0, width: 0, normalX: 0, normalWidth: 0 } - hoveredLayout.current = null; - selectedLayout.current = null; + hoveredLayout.current = null + selectedLayout.current = null setPicturesLayout( cameraPoses.map((d, i) => { - const isSelected = selected && d.id === selected.id; - const isHovered = hovered && d.id === hovered.id; + const isSelected = selected && d.id === selected.id + const isHovered = hovered && d.id === hovered.id // e - 1 because Colmap image ids are [1; N] and dataset are from [0; N-1] - const x = last.x + last.width; + const x = last.x + last.width const width = selected ? isSelected ? sizes.large : sizes.block : isHovered - ? sizes.large - : sizes.block; - const normalX = last.normalX + last.normalWidth; + ? sizes.large + : sizes.block + const normalX = last.normalX + last.normalWidth const obj = { item: { ...d, photoUri: imageSet ? imageSet[i].path : null, - texture: imageSet ? imageSet[i].texture : null, + texture: imageSet ? imageSet[i].texture : null }, x, normalX, @@ -192,32 +192,32 @@ export default function Carousel() { normalWidth: sizes.normal, height, hovered: isHovered, - selected: isSelected, - }; + selected: isSelected + } - last = obj; + last = obj - if (isHovered) hoveredLayout.current = obj; - if (isSelected) selectedLayout.current = obj; + if (isHovered) hoveredLayout.current = obj + if (isSelected) selectedLayout.current = obj - return obj; + return obj }) - ); + ) } - }, [windowSider, context, hovered, selected, urlList, cameraPoses]); + }, [windowSider, context, hovered, selected, urlList, cameraPoses]) if (context) { - const { width, height } = getSize(containerRef.current); - context.clearRect(0, 0, width, height); + const { width, height } = getSize(containerRef.current) + context.clearRect(0, 0, width, height) picturesLayout.forEach((d, i) => { if (imgs[d.item.photoUri]) { - const imgWidth = imgs[d.item.photoUri].width; - const imgHeight = imgs[d.item.photoUri].height; - const ratio = imgWidth / large; - const sx = imgWidth / 2 - d.width * ratio * 0.5; - const sy = 0; + const imgWidth = imgs[d.item.photoUri].width + const imgHeight = imgs[d.item.photoUri].height + const ratio = imgWidth / large + const sx = imgWidth / 2 - d.width * ratio * 0.5 + const sy = 0 - context.globalAlpha = d.hovered || d.selected ? 1 : 0.5; + context.globalAlpha = d.hovered || d.selected ? 1 : 0.5 context.drawImage( imgs[d.item.photoUri], sx, @@ -229,54 +229,53 @@ export default function Carousel() { 0, d.width, height - ); - if(!d.item.isMatched) - { - context.fillStyle = "rgba(255, 85, 95, 0.4)"; - context.fillRect(d.x, 0, d.width, imgHeight); + ) + if (!d.item.isMatched) { + context.fillStyle = 'rgba(255, 85, 95, 0.4)' + context.fillRect(d.x, 0, d.width, imgHeight) } } else { - context.fillStyle = d.hovered ? "white" : "grey"; - context.fillRect(d.x, 0, d.width, height); - context.fillStyle = "black"; + context.fillStyle = d.hovered ? 'white' : 'grey' + context.fillRect(d.x, 0, d.width, height) + context.fillStyle = 'black' } - }); + }) } useEffect(() => { const handler = (e) => { - setDragging(false); - document.body.style.cursor = null; - }; + setDragging(false) + document.body.style.cursor = null + } const moveHander = (e) => { if (dragging && e.movementX !== 0) { const dX = e.movementX < 0 ? e.clientX - (dragging.from - dragging.triggerLeft) : e.clientX - - (dragging.from - (dragging.triggerLeft + dragging.triggerWidth)); + (dragging.from - (dragging.triggerLeft + dragging.triggerWidth)) const pictureDragged = picturesLayout.find( (d) => d.x <= dX && d.x + d.width >= dX - ); + ) if (pictureDragged) { - setSelected(pictureDragged.item); + setSelected(pictureDragged.item) } } - }; + } if (dragging) { - window.addEventListener("mouseup", handler); - window.addEventListener("mousemove", moveHander); + window.addEventListener('mouseup', handler) + window.addEventListener('mousemove', moveHander) } else { - window.removeEventListener("mouseup", handler); - window.removeEventListener("mousemove", moveHander); + window.removeEventListener('mouseup', handler) + window.removeEventListener('mousemove', moveHander) } return () => { - window.removeEventListener("mouseup", handler); - window.removeEventListener("mousemove", moveHander); - }; - }, [dragging, picturesLayout, selectedLayout]); + window.removeEventListener('mouseup', handler) + window.removeEventListener('mousemove', moveHander) + } + }, [dragging, picturesLayout, selectedLayout]) const eventsFn = { onMouseMove: (e) => { @@ -287,24 +286,24 @@ export default function Carousel() { hoveredLayout.current.width * 0.5 + hoveredLayout.current.normalWidth : e.clientX + hoveredLayout.current.width * 0.5 - : e.clientX; + : e.clientX const pictureHovered = picturesLayout.find( (d) => d.x <= dX && d.x + d.width >= dX - ); + ) if (pictureHovered && hovered !== pictureHovered.item) { - setHovered(pictureHovered ? pictureHovered.item : null); + setHovered(pictureHovered ? pictureHovered.item : null) } }, onMouseOut: (e) => { - setHovered(null); + setHovered(null) }, onClick: () => { if (hovered) { - setSelected(selected && selected.id === hovered.id ? null : hovered); + setSelected(selected && selected.id === hovered.id ? null : hovered) } - }, - }; + } + } return ( { - const bb = e.target.getBoundingClientRect(); - document.body.style.cursor = "grabbing"; + const bb = e.target.getBoundingClientRect() + document.body.style.cursor = 'grabbing' setDragging({ from: e.clientX, triggerLeft: bb.left, - triggerWidth: bb.width, - }); + triggerWidth: bb.width + }) }} /> @@ -354,12 +353,12 @@ export default function Carousel() { )} - ); + ) } const SVGCartridge = memo( ({ hoveredLayout, selectedLayout, large, eventsFn }) => { - const intl = useFormatMessage(); + const intl = useFormatMessage() return ( @@ -379,7 +378,7 @@ const SVGCartridge = memo( ry={2} /> - {intl("carrousel-open")} + {intl('carrousel-open')} @@ -395,14 +394,14 @@ const SVGCartridge = memo( ry={2} /> - {intl("carrousel-close")} + {intl('carrousel-close')} )} - + - ); + ) } -); +) diff --git a/src/Viewer/Interactors/Tools/index.js b/src/Viewer/Interactors/Tools/index.js index 1f19a81..72f7444 100644 --- a/src/Viewer/Interactors/Tools/index.js +++ b/src/Viewer/Interactors/Tools/index.js @@ -20,7 +20,7 @@ export const tools = { }, misc: { ruler: 6, - aabb:7, + aabb: 7, snapshot: 8, photoSets: 9 } diff --git a/src/Viewer/Interactors/icons/index.js b/src/Viewer/Interactors/icons/index.js index 8ea791c..044799d 100644 --- a/src/Viewer/Interactors/icons/index.js +++ b/src/Viewer/Interactors/icons/index.js @@ -181,7 +181,7 @@ export const RulerIcon = IconHOC((props) => { raw={rulerRaw} alt='ruler icon' /> -}) +}) export const BackgroundColorIcon = IconHOC((props) => { return setLayers({ ...layers, axisAlignedBoundingBox: !layers.axisAlignedBoundingBox})} + onClick={() => setLayers({ ...layers, axisAlignedBoundingBox: !layers.axisAlignedBoundingBox })} > { interactors = getAllByTestId(/interactor/i) }) -//it('renders correctly', () => { +// it('renders correctly', () => { // expect(interactors).toBeTruthy() // expect(interactors.length).toBe(Object.keys(originalMockLayers).length) -//}) +// }) it('setter is not called when clicking on disabled interactor', () => { expect(mockSetLayers).not.toHaveBeenCalled() diff --git a/src/Viewer/Interactors/misc.js b/src/Viewer/Interactors/misc.js index 25922bc..578ec03 100644 --- a/src/Viewer/Interactors/misc.js +++ b/src/Viewer/Interactors/misc.js @@ -3,8 +3,8 @@ import { FormattedMessage } from 'react-intl' import styled from '@emotion/styled' import { useMisc, useCarousel } from 'flow/settings/accessors' -import { useSnapshot, useRuler, useAxisAlignedBoundingBox, useDefaultColors, useColor } - from 'flow/interactions/accessors' +import { useSnapshot, useRuler, useAxisAlignedBoundingBox, useDefaultColors, useColor } +from 'flow/interactions/accessors' import ToolButton, { tools } from 'Viewer/Interactors/Tools' import { H3, H2 } from 'common/styles/UI/Text/titles' @@ -36,7 +36,6 @@ export const Container = styled.div({ } }) - const ChooserContainer = styled.div({ display: 'flex', flexDirection: 'column' @@ -115,70 +114,68 @@ const DownloadButtonImage = styled.div({ cursor: 'pointer' }) -function Point3D (props) -{ +function Point3D (props) { const [aabb, setAABB] = useAxisAlignedBoundingBox() const id = props.id return (
-
X
+
X
{ setAABB({ ...aabb, [id]: { ...aabb[id], - x: isNaN(event.target.value) ? 0 : event.target.value, - }, - }); + x: isNaN(event.target.value) ? 0 : event.target.value + } + }) }} value={aabb[id].x} /> -
Y
+
Y
{ setAABB({ ...aabb, [id]: { ...aabb[id], - y: isNaN(event.target.value) ? 0 : event.target.value, - }, - }); + y: isNaN(event.target.value) ? 0 : event.target.value + } + }) }} value={aabb[id].y} /> -
Z
+
Z
{ setAABB({ ...aabb, [id]: { ...aabb[id], - z: isNaN(event.target.value) ? 0 : event.target.value, - }, - }); + z: isNaN(event.target.value) ? 0 : event.target.value + } + }) }} value={aabb[id].z} />
- ); + ) } - function PhotoSetButton ({ set }) { const [carousel, setCarousel] = useCarousel() return } - export default function () { const [snapshot, setSnapshot] = useSnapshot() const [snapWidth, setSnapWidth] = useState(0) @@ -275,130 +271,129 @@ export default function () { } >

- +

- -

- + +

+

- + setAABB({ ...aabb, enforceReset: true })} /> -
+
{ - if(!isNaN(val)) - return parseFloat(val); + { + bounding_box: { + x: [aabb.min.x, aabb.max.x], + y: [aabb.min.y, aabb.max.y], + z: [aabb.min.z, aabb.max.z] + } + }, + (key, val) => { + if (!isNaN(val)) { return parseFloat(val) } - return val; - }, - 2 - )}> - + return val + }, + 2 + )}> +
} >

- +

{ - const value = e.target.value > 0.0001 ? e.target.value : 0.0001; - setMisc({ ...misc, scale: value }); + const value = e.target.value > 0.0001 ? e.target.value : 0.0001 + setMisc({ ...misc, scale: value }) }} value={misc.scale} - />{" "} + />{' '}

cm

{ if (!ruler.measuring) { - setRuler({ ...ruler, scaling: !ruler.scaling }); + setRuler({ ...ruler, scaling: !ruler.scaling }) } }} >

- {" "} - {" "} + {' '} + {' '}

- {" "} - {" "} + {' '} + {' '}

{ if (!ruler.scaling) { setRuler({ ...ruler, - measuring: !ruler.measuring, - }); + measuring: !ruler.measuring + }) } }} >

- {" "} - {" "} + {' '} + {' '}

@@ -406,26 +401,26 @@ export default function () {

-

- +

+

} interactor={{ - isButton: true, + isButton: true }} - tooltipId="tooltip-snapshot" + tooltipId='tooltip-snapshot' >
{ - setSnapWidth(snapshot.trueResolution.width); - setSnapHeight(snapshot.trueResolution.height); + setSnapWidth(snapshot.trueResolution.width) + setSnapHeight(snapshot.trueResolution.height) }} />

- {" "} - {" "} + {' '} + {' '}

{ setSnapWidth( parseInt(Math.min(Math.max(e.target.value, 0), 4096)) - ); + ) }} value={ snapWidth || (snapshot.trueResolution ? snapshot.trueResolution.width : 0) } - />{" "} + />{' '}

X

{ setSnapHeight( parseInt(Math.min(Math.max(e.target.value, 0), 2160)) - ); + ) }} value={ snapHeight || @@ -519,16 +514,16 @@ export default function () {
{snapshot.image ? (
-

- +

+

{ setSnapshot({ ...snapshot, - image: null, - }); + image: null + }) }} />

@@ -538,8 +533,8 @@ export default function () { onGenerateClick={() => { setSnapshot({ ...snapshot, - snapResolution: { width: snapWidth, height: snapHeight }, - }); + snapResolution: { width: snapWidth, height: snapHeight } + }) }} />
@@ -553,52 +548,52 @@ export default function () { /> } interactor={{ - isButton: true, + isButton: true }} - tooltipId="tooltip-photoset" + tooltipId='tooltip-photoset' > -
+
- - - + + +
} - > -
- } + > +
+ { - setColors({ - ...colors, - background: {rgb: color.hex, a: 1.0} - }) - window.localStorage.setItem('defaultBgroundColor', color.hex) + onChange={ + (color) => { + setColors({ + ...colors, + background: { rgb: color.hex, a: 1.0 } + }) + window.localStorage.setItem('defaultBgroundColor', color.hex) + } + } + color={colors.background.rgb} + /> +
+ { + window.localStorage.setItem('defaultBgroundColor', bgroundColor) + resetDefaultColor('background') } } - color={colors.background.rgb} /> -
- { - window.localStorage.setItem('defaultBgroundColor', bgroundColor) - resetDefaultColor('background') - } - } - /> -
+ - ); + ) } diff --git a/src/Viewer/Interactors/tools.js b/src/Viewer/Interactors/tools.js index 979eb17..c138b8f 100644 --- a/src/Viewer/Interactors/tools.js +++ b/src/Viewer/Interactors/tools.js @@ -1,7 +1,7 @@ -import React, { useState, useEffect } from "react"; -import styled from "@emotion/styled"; -import { SketchPicker } from "react-color"; -import { FormattedMessage } from "react-intl"; +import React, { useState, useEffect } from 'react' +import styled from '@emotion/styled' +import { SketchPicker } from 'react-color' +import { FormattedMessage } from 'react-intl' import { useSelectedAngle, @@ -9,90 +9,90 @@ import { useDefaultColors, usePointCloudZoom, usePointCloudSize -} from "flow/interactions/accessors"; -import { useLayerTools, useLayers, } from "flow/settings/accessors"; -import { useSegmentedPointCloud } from "flow/scans/accessors"; +} from 'flow/interactions/accessors' +import { useLayerTools, useLayers } from 'flow/settings/accessors' +import { useSegmentedPointCloud } from 'flow/scans/accessors' -import { PaintIcon } from "Viewer/Interactors/icons"; -import { ResetButton } from "rd/UI/Buttons"; -import { H3 } from "common/styles/UI/Text/titles"; -import ToolButton, { tools } from "Viewer/Interactors/Tools"; -import MenuBox, { MenuBoxContent } from "rd/UI/MenuBox"; -import Slider from "rd/UI/Slider"; +import { PaintIcon } from 'Viewer/Interactors/icons' +import { ResetButton } from 'rd/UI/Buttons' +import { H3 } from 'common/styles/UI/Text/titles' +import ToolButton, { tools } from 'Viewer/Interactors/Tools' +import MenuBox, { MenuBoxContent } from 'rd/UI/MenuBox' +import Slider from 'rd/UI/Slider' const hex2RGB = (hex) => { return { r: parseInt(hex[1] + hex[2], 16), g: parseInt(hex[3] + hex[4], 16), - b: parseInt(hex[5] + hex[6], 16), - }; -}; + b: parseInt(hex[5] + hex[6], 16) + } +} export const Container = styled.div({ - position: "absolute", + position: 'absolute', top: 60, left: 20, - display: "flex", + display: 'flex', - "& :first-of-type > div": { - borderRadius: "2px 0 0 2px", + '& :first-of-type > div': { + borderRadius: '2px 0 0 2px' }, - "& :last-of-type > div": { - borderRadius: "0 2px 2px 0", - }, -}); + '& :last-of-type > div': { + borderRadius: '0 2px 2px 0' + } +}) const LegendContainer = styled.div({ - display: "flex", - flexDirection: "row", - justifyContent: "space-between", - alignItems: "center", -}); + display: 'flex', + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center' +}) const ColumnContainer = styled.div({}, (props) => { return { - display: "flex", - visibility: props.displayed ? "visible" : "hidden", - flexDirection: "column", + display: 'flex', + visibility: props.displayed ? 'visible' : 'hidden', + flexDirection: 'column', marginLeft: 0, - marginRight: 0, - }; -}); + marginRight: 0 + } +}) -const ToolContainer = styled(Container)({}); +const ToolContainer = styled(Container)({}) // Setting the default color values to make sure every component has a base color value in addition to the one given in their file let defaults = { - defaultOrgan1Color: "#BD10E0", - defaultOrgan2Color: "#E79DF6", - defaultOrganOpacity: "0.5", - defaultMeshColor: "#96c0a7", - defaultMeshOpacity: "0.5", - defaultPointCloudColor: "#f8de96", - defaultPointCloudOpacity: "1", - defaultPointCloudSize: "1000", - defaultSkeletonColor: "#D0021B", - defaultSkeletonOpacity: "0.7", -}; + defaultOrgan1Color: '#BD10E0', + defaultOrgan2Color: '#E79DF6', + defaultOrganOpacity: '0.5', + defaultMeshColor: '#96c0a7', + defaultMeshOpacity: '0.5', + defaultPointCloudColor: '#f8de96', + defaultPointCloudOpacity: '1', + defaultPointCloudSize: '1000', + defaultSkeletonColor: '#D0021B', + defaultSkeletonOpacity: '0.7' +} for (let key in defaults) { if (!window.localStorage.getItem(key)) { - window.localStorage.setItem(key, defaults[key]); + window.localStorage.setItem(key, defaults[key]) } } -export default function MiscInteractors() { - const [selectedAngle] = useSelectedAngle(); - const [colors, setColors] = useColor(); - const [resetDefaultColor] = useDefaultColors(); - const [layerTools] = useLayerTools(); - const [layers] = useLayers(); - const [labels, setLabels] = useState(); - const [, segmentation] = useSegmentedPointCloud(); - const [legendPicker, setLegendPicker] = useState(); - const [pointCloudZoom, setPointCloudZoom] = usePointCloudZoom(); - const [pointCloudSize, setPointCloudSize] = usePointCloudSize(); +export default function MiscInteractors () { + const [selectedAngle] = useSelectedAngle() + const [colors, setColors] = useColor() + const [resetDefaultColor] = useDefaultColors() + const [layerTools] = useLayerTools() + const [layers] = useLayers() + const [labels, setLabels] = useState() + const [, segmentation] = useSegmentedPointCloud() + const [legendPicker, setLegendPicker] = useState() + const [pointCloudZoom, setPointCloudZoom] = usePointCloudZoom() + const [pointCloudSize, setPointCloudSize] = usePointCloudSize() useEffect(() => { if (segmentation && segmentation.labels) { @@ -100,12 +100,12 @@ export default function MiscInteractors() { segmentation.labels.filter( (value, index, self) => self.indexOf(value) === index ) - ); + ) } - }, [segmentation]); - + }, [segmentation]) + // This is probably the worst part of the interface. This is the row of tools appearing when you click on various layers. - // There is no links between the layer buttons and the tools associated to it. + // There is no links between the layer buttons and the tools associated to it. // Improvement : Rework the interactors to have tools associated to specific layers. Its mostly the component hierarchy with some CSS // most of what's done is working fine return ( @@ -116,9 +116,9 @@ export default function MiscInteractors() { tool={tools.colorPickers.mesh} layer={layers.mesh} interactor={{ - isButton: true, + isButton: true }} - tooltipId="tooltip-mesh-color-picker" + tooltipId='tooltip-mesh-color-picker' icon={ { - if (color.hex === "transparent") return; + if (color.hex === 'transparent') return setColors({ ...colors, - mesh: { rgb: color.hex, a: color.rgb.a }, - }); - window.localStorage.setItem("defaultMeshColor", color.hex); + mesh: { rgb: color.hex, a: color.rgb.a } + }) + window.localStorage.setItem('defaultMeshColor', color.hex) window.localStorage.setItem( - "defaultMeshOpacity", + 'defaultMeshOpacity', color.rgb.a.toString() - ); + ) }} // color={{ ...hex2RGB(colors.mesh.rgb), a: colors.mesh.a }} color={{ - ...hex2RGB(window.localStorage.getItem("defaultMeshColor")), - a: window.localStorage.getItem("defaultMeshOpacity"), + ...hex2RGB(window.localStorage.getItem('defaultMeshColor')), + a: window.localStorage.getItem('defaultMeshOpacity') }} /> { window.localStorage.setItem( - "defaultMeshColor", + 'defaultMeshColor', defaults.defaultMeshColor - ); + ) window.localStorage.setItem( - "defaultMeshOpacity", + 'defaultMeshOpacity', defaults.defaultMeshOpacity - ); - resetDefaultColor("mesh"); + ) + resetDefaultColor('mesh') }} /> @@ -165,9 +165,9 @@ export default function MiscInteractors() { tool={tools.colorPickers.pointCloud} layer={layers.pointCloud} interactor={{ - isButton: true, + isButton: true }} - tooltipId={"tooltip-point-cloud-color-picker"} + tooltipId={'tooltip-point-cloud-color-picker'} icon={ { - if (color.hex === "transparent") return; + if (color.hex === 'transparent') return setColors({ ...colors, - pointCloud: { rgb: color.hex, a: color.rgb.a }, - }); - window.localStorage.setItem("defaultPointCloudColor", color.hex); + pointCloud: { rgb: color.hex, a: color.rgb.a } + }) + window.localStorage.setItem('defaultPointCloudColor', color.hex) window.localStorage.setItem( - "defaultPointCloudOpacity", + 'defaultPointCloudOpacity', color.rgb.a.toString() - ); + ) }} // color={{ ...hex2RGB(colors.pointCloud.rgb), a: colors.pointCloud.a }} color={{ - ...hex2RGB(window.localStorage.getItem("defaultPointCloudColor")), - a: window.localStorage.getItem("defaultPointCloudOpacity"), + ...hex2RGB(window.localStorage.getItem('defaultPointCloudColor')), + a: window.localStorage.getItem('defaultPointCloudOpacity') }} /> { - resetDefaultColor("pointCloud"); + resetDefaultColor('pointCloud') window.localStorage.setItem( - "defaultPointCloudColor", + 'defaultPointCloudColor', defaults.defaultPointCloudColor - ); + ) window.localStorage.setItem( - "defaultPointCloudOpacity", + 'defaultPointCloudOpacity', defaults.defaultPointCloudOpacity - ); + ) }} /> @@ -216,9 +216,9 @@ export default function MiscInteractors() { tool={tools.colorPickers.segmentedPointCloud} layer={layers.segmentedPointCloud} Interactor={{ - isButton: true, + isButton: true }} - tooltipId={"tooltip-segmentedpointcloud-color-picker"} + tooltipId={'tooltip-segmentedpointcloud-color-picker'} icon={ {labels && colors.segmentedPointCloud.length ? labels.map((d, i) => { - return ( - -

{d}

- { - setLegendPicker(null); + return ( + +

{d}

+ { + setLegendPicker(null) + }} + > +
-
{ - setLegendPicker(i); + onClick={() => { + setLegendPicker(i) + }} + /> + + { + let copy = colors.segmentedPointCloud.slice() + copy[i] = val.hex + setColors({ ...colors, segmentedPointCloud: copy }) + window.localStorage.setItem( + 'defaultSegmentedColors', + JSON.stringify(copy) + ) }} + color={colors.segmentedPointCloud[i]} /> - - { - let copy = colors.segmentedPointCloud.slice(); - copy[i] = val.hex; - setColors({ ...colors, segmentedPointCloud: copy }); - window.localStorage.setItem( - "defaultSegmentedColors", - JSON.stringify(copy) - ); - }} - color={colors.segmentedPointCloud[i]} - /> - - - - ); - }) + + + + ) + }) : null} @@ -278,9 +278,9 @@ export default function MiscInteractors() { tool={tools.colorPickers.skeleton} layer={layers.skeleton} interactor={{ - isButton: true, + isButton: true }} - tooltipId={"tooltip-skeleton-color-picker"} + tooltipId={'tooltip-skeleton-color-picker'} icon={ { - if (color.hex === "transparent") return; + if (color.hex === 'transparent') return setColors({ ...colors, - skeleton: { rgb: color.hex, a: color.rgb.a }, - }); - window.localStorage.setItem("defaultSkeletonColor", color.hex); + skeleton: { rgb: color.hex, a: color.rgb.a } + }) + window.localStorage.setItem('defaultSkeletonColor', color.hex) window.localStorage.setItem( - "defaultSkeletonOpacity", + 'defaultSkeletonOpacity', color.rgb.a.toString() - ); + ) }} // color={{ ...hex2RGB(colors.skeleton.rgb), a: colors.skeleton.a }} color={{ - ...hex2RGB(window.localStorage.getItem("defaultSkeletonColor")), - a: window.localStorage.getItem("defaultSkeletonOpacity"), + ...hex2RGB(window.localStorage.getItem('defaultSkeletonColor')), + a: window.localStorage.getItem('defaultSkeletonOpacity') }} /> { - resetDefaultColor("skeleton"); + resetDefaultColor('skeleton') window.localStorage.setItem( - "defaultSkeletonColor", + 'defaultSkeletonColor', defaults.defaultSkeletonColor - ); + ) window.localStorage.setItem( - "defaultSkeletonOpacity", + 'defaultSkeletonOpacity', defaults.defaultSkeletonOpacity - ); + ) }} /> @@ -329,12 +329,12 @@ export default function MiscInteractors() { tool={tools.colorPickers.organs} layer={layers.angles} interactor={{ - isButton: true, + isButton: true }} tooltipId={ selectedAngle === undefined || selectedAngle === null - ? "tooltip-organ-global-color-picker" - : "tooltip-organ-color-picker" + ? 'tooltip-organ-global-color-picker' + : 'tooltip-organ-color-picker' } icon={ { - if (color.hex === "transparent") return; - let color2 = color.hsl; + if (color.hex === 'transparent') return + let color2 = color.hsl // Use a lighter color for the second organ of the pair - color2.l += 0.3; + color2.l += 0.3 /* This is a bit ugly but very useful to change the brightness of the color */ const color2String = - "hsl(" + + 'hsl(' + Math.round(color2.h) + - ", " + + ', ' + Math.round(color2.s * 100) + - "%, " + + '%, ' + Math.round(color2.l * 100) + - "%)"; + '%)' if (selectedAngle !== undefined && selectedAngle !== null) { // We slice the array because it has to be an immutable change - let copy = colors.organs.slice(); - const next = selectedAngle + 1; - copy[selectedAngle] = { rgb: color.hex, a: color.rgb.a }; - copy[next] = { rgb: color2String, a: color.rgb.a }; + let copy = colors.organs.slice() + const next = selectedAngle + 1 + copy[selectedAngle] = { rgb: color.hex, a: color.rgb.a } + copy[next] = { rgb: color2String, a: color.rgb.a } setColors({ ...colors, - organs: copy, - }); + organs: copy + }) } else { setColors({ ...colors, globalOrganColors: [ { rgb: color.hex, a: color.rgb.a }, - { rgb: color2String, a: color.rgb.a }, - ], - }); + { rgb: color2String, a: color.rgb.a } + ] + }) } - window.localStorage.setItem("defaultOrgan1Color", color.hex); - window.localStorage.setItem("defaultOrgan2Color", color2String); + window.localStorage.setItem('defaultOrgan1Color', color.hex) + window.localStorage.setItem('defaultOrgan2Color', color2String) window.localStorage.setItem( - "defaultOrganOpacity", + 'defaultOrganOpacity', color.rgb.a.toString() - ); + ) }} color={ selectedAngle !== undefined && selectedAngle !== null && colors.organs[selectedAngle] ? { - ...hex2RGB( - window.localStorage.getItem("defaultOrgan1Color") - ), // hex2RGB(colors.organs[selectedAngle].rgb) - a: window.localStorage.getItem("defaultOrganOpacity"), - } + ...hex2RGB( + window.localStorage.getItem('defaultOrgan1Color') + ), // hex2RGB(colors.organs[selectedAngle].rgb) + a: window.localStorage.getItem('defaultOrganOpacity') + } : { - ...hex2RGB( - window.localStorage.getItem("defaultOrgan1Color") - ), // hex2RGB(colors.organs[0].rgb) - a: window.localStorage.getItem("defaultOrganOpacity"), - } + ...hex2RGB( + window.localStorage.getItem('defaultOrgan1Color') + ), // hex2RGB(colors.organs[0].rgb) + a: window.localStorage.getItem('defaultOrganOpacity') + } } /> { if (selectedAngle !== undefined && selectedAngle !== null) { if (colors.organs.length > selectedAngle + 1) { - let copy = colors.organs.slice(); - copy[selectedAngle] = null; - copy[selectedAngle + 1] = null; + let copy = colors.organs.slice() + copy[selectedAngle] = null + copy[selectedAngle + 1] = null setColors({ ...colors, - organs: copy, - }); + organs: copy + }) } } else { window.localStorage.setItem( - "defaultOrgan1Color", + 'defaultOrgan1Color', defaults.defaultOrgan1Color - ); + ) window.localStorage.setItem( - "defaultOrgan2Color", + 'defaultOrgan2Color', defaults.defaultOrgan2Color - ); + ) window.localStorage.setItem( - "defaultOrganOpacity", + 'defaultOrganOpacity', defaults.defaultOrganOpacity - ); - resetDefaultColor("globalOrganColors"); + ) + resetDefaultColor('globalOrganColors') } }} /> @@ -442,8 +442,8 @@ export default function MiscInteractors() { layers.pointCloudGroundTruth } > -

- +

+

-

- +

+

- ); + ) } diff --git a/src/Viewer/World/entities/aabb.js b/src/Viewer/World/entities/aabb.js index 068a22e..6402a8a 100644 --- a/src/Viewer/World/entities/aabb.js +++ b/src/Viewer/World/entities/aabb.js @@ -1,68 +1,63 @@ /** - * This is unused code. + * This is unused code. * */ -import { Vector3, Box3, Box3Helper } from "three"; +import { Vector3, Box3, Box3Helper } from 'three' export default class AABB { - constructor(parent, box) { + constructor (parent, box) { this.ogBox = new Box3( - new Vector3(parseFloat(box.min.x), parseFloat(box.min.y), parseFloat(box.min.z)), + new Vector3(parseFloat(box.min.x), parseFloat(box.min.y), parseFloat(box.min.z)), new Vector3(parseFloat(box.max.x), parseFloat(box.max.y), parseFloat(box.max.z)) ) - - this.object = new Box3Helper(this.ogBox, 0xffffff); - this.object.renderOrder = -1; - if(parent) parent.add(this.object); + + this.object = new Box3Helper(this.ogBox, 0xffffff) + this.object.renderOrder = -1 + if (parent) parent.add(this.object) } - setVisible(boolean) - { - this.object.visible = boolean; + setVisible (boolean) { + this.object.visible = boolean } - setBoundingBox(aabb) { + setBoundingBox (aabb) { // We could maybe do without creating a new GeometryBuffer // This is left as excercise for the next intern here :) this.box = new Box3( - new Vector3(parseFloat(aabb.min.x), parseFloat(aabb.min.y), parseFloat(aabb.min.z)), + new Vector3(parseFloat(aabb.min.x), parseFloat(aabb.min.y), parseFloat(aabb.min.z)), new Vector3(parseFloat(aabb.max.x), parseFloat(aabb.max.y), parseFloat(aabb.max.z)) ) - + let oldObj = this.object - const newObj = new Box3Helper(this.box, 0xffffff); + const newObj = new Box3Helper(this.box, 0xffffff) newObj.visible = oldObj.visible - //oldObj.visible = false + // oldObj.visible = false oldObj.parent.add(newObj) newObj.parent.remove(oldObj) this.object = newObj - } - resetBoundingBox() - { + resetBoundingBox () { let oldObj = this.object - const newObj = new Box3Helper(this.ogBox, 0xffffff); + const newObj = new Box3Helper(this.ogBox, 0xffffff) newObj.visible = oldObj.visible - //oldObj.visible = false + // oldObj.visible = false oldObj.parent.add(newObj) newObj.parent.remove(oldObj) this.object = newObj } - getBoundingBox() - { - + getBoundingBox () { const ret = { min: { x: this.object.box.min.x.toFixed(4), y: this.object.box.min.y.toFixed(4), - z: this.object.box.min.z.toFixed(4), + z: this.object.box.min.z.toFixed(4) }, max: { x: this.object.box.max.x.toFixed(4), y: this.object.box.max.y.toFixed(4), - z: this.object.box.max.z.toFixed(4), + z: this.object.box.max.z.toFixed(4) } } return ret diff --git a/src/Viewer/World/entities/pointCloud.js b/src/Viewer/World/entities/pointCloud.js index 52982e1..9c434ec 100644 --- a/src/Viewer/World/entities/pointCloud.js +++ b/src/Viewer/World/entities/pointCloud.js @@ -26,7 +26,7 @@ License along with this program. If not, see . */ -import * as THREE from "three"; +import * as THREE from 'three' const vertexShader = ` uniform vec3 color; @@ -44,7 +44,7 @@ const vertexShader = ` gl_PointSize = ratio * zoom * clamp(1.0 * ( 200.0 / -mvPosition.z ), 0.8, 500.0); gl_Position = projectionMatrix * mvPosition; } -`; +` const fragmentShader = ` varying vec3 vColor; @@ -54,131 +54,130 @@ const fragmentShader = ` if ( length( gl_PointCoord - vec2( 0.5, 0.5 ) ) > 0.475 ) discard; gl_FragColor = vec4( vColor, opacity ); } -`; +` export default class PointCloud { - constructor(geometry, parent) { - this.geometry = geometry; - this.vertices = this.bufferToVector3(geometry.getAttribute("position")); - this.geometry.computeVertexNormals(); - const pixelRatio = window.devicePixelRatio ? window.devicePixelRatio : 1; - - var opacity = window.localStorage.getItem("defaultPointCloudOpacity"); - var color = window.localStorage.getItem("defaultPointCloudColor"); + constructor (geometry, parent) { + this.geometry = geometry + this.vertices = this.bufferToVector3(geometry.getAttribute('position')) + this.geometry.computeVertexNormals() + const pixelRatio = window.devicePixelRatio ? window.devicePixelRatio : 1 + + var opacity = window.localStorage.getItem('defaultPointCloudOpacity') + var color = window.localStorage.getItem('defaultPointCloudColor') this.material = new THREE.ShaderMaterial({ uniforms: { opacity: { value: opacity != null ? parseFloat(opacity) : 1 }, - ratio: { type: "f", value: pixelRatio }, + ratio: { type: 'f', value: pixelRatio }, color: { - type: "c", + type: 'c', value: - color != null ? new THREE.Color(color) : new THREE.Color("#f8de96"), + color != null ? new THREE.Color(color) : new THREE.Color('#f8de96') }, - zoom: { type: "f", value: 1 }, + zoom: { type: 'f', value: 1 } }, vertexShader, - fragmentShader, - }); + fragmentShader + }) - this.object = new THREE.Points(this.geometry, this.material); - this.object.renderOrder = -1; + this.object = new THREE.Points(this.geometry, this.material) + this.object.renderOrder = -1 - if (parent) parent.add(this.object); - return this; + if (parent) parent.add(this.object) + return this } - bufferToVector3(attribute) { - const values = attribute; + bufferToVector3 (attribute) { + const values = attribute let vectors = Array.from( { length: attribute.count }, () => new THREE.Vector3() - ); - for (let v = 0; v < values.count; v++) - vectors[v].fromBufferAttribute(values, v); + ) + for (let v = 0; v < values.count; v++) { vectors[v].fromBufferAttribute(values, v) } - return vectors; + return vectors } - setPosition(x = 0, y = 0, z = 0) { - this.object.position.x = x; - this.object.position.y = y; - this.object.position.z = z; + setPosition (x = 0, y = 0, z = 0) { + this.object.position.x = x + this.object.position.y = y + this.object.position.z = z - return this; + return this } - setVisible(boolean) { - this.object.visible = boolean; + setVisible (boolean) { + this.object.visible = boolean } - setZoomLevel(zoomLevel) { - this.material.uniforms.zoom.value = zoomLevel; + setZoomLevel (zoomLevel) { + this.material.uniforms.zoom.value = zoomLevel } - setColor(color) { + setColor (color) { if (color && color.rgb && color.a) { - this.material.uniforms.color.value = new THREE.Color(color.rgb); - this.material.uniforms.opacity.value = color.a; + this.material.uniforms.color.value = new THREE.Color(color.rgb) + this.material.uniforms.opacity.value = color.a } } // setCloudResolution(sampleSize) { // } - getRandomSampleOfIndicesFromSize(indicesRange, sampleSize) { - if (this.vertices.length < sampleSize) return; - const indices_ = Array.from({ length: indicesRange }, (x, i) => i); - let N = indicesRange; - let indices = Array.from({ length: sampleSize }, (x, i) => -1); - let i = 0; + getRandomSampleOfIndicesFromSize (indicesRange, sampleSize) { + if (this.vertices.length < sampleSize) return + const indices_ = Array.from({ length: indicesRange }, (x, i) => i) + let N = indicesRange + let indices = Array.from({ length: sampleSize }, (x, i) => -1) + let i = 0 - let index = 0; - let n = sampleSize; + let index = 0 + let n = sampleSize while (n > 0) { // Step 1: [Generate U.] Generate a random variate U that is uniformly distributed between 0 and 1. - const U = Math.random(); + const U = Math.random() // Step 2: [Test.] If N * U > n, go to Step 4. if (N * U <= n) { // Step 3: [Select.] Select the next record in the file for the sample, and set n : = n - 1. - indices[i++] = indices_[index]; - --n; + indices[i++] = indices_[index] + --n } // Step 4: [Don't select.] Skip over the next record (do not include it in the sample). // Set N : = N - 1. - --N; - ++index; + --N + ++index // If n > 0, then return to Step 1; otherwise, the sample is complete and the algorithm terminates. } - return indices; + return indices } - setCloudResolution(sampleSize) { - sampleSize = Math.round(sampleSize * this.vertices.length); + setCloudResolution (sampleSize) { + sampleSize = Math.round(sampleSize * this.vertices.length) console.log(sampleSize) const indices = this.getRandomSampleOfIndicesFromSize( this.vertices.length, sampleSize - ); + ) for (const key in this.geometry.attributes) { - let attr = this.geometry.getAttribute(key); + let attr = this.geometry.getAttribute(key) for (let i = 0; i < sampleSize; i++) { - const newX = attr.array[indices[i] * 3]; - const newY = attr.array[indices[i] * 3 + 1]; - const newZ = attr.array[indices[i] * 3 + 2]; + const newX = attr.array[indices[i] * 3] + const newY = attr.array[indices[i] * 3 + 1] + const newZ = attr.array[indices[i] * 3 + 2] - attr.array[indices[i] * 3] = attr.array[i * 3]; - attr.array[indices[i] * 3 + 1] = attr.array[i * 3 + 1]; - attr.array[indices[i] * 3 + 2] = attr.array[i * 3 + 2]; + attr.array[indices[i] * 3] = attr.array[i * 3] + attr.array[indices[i] * 3 + 1] = attr.array[i * 3 + 1] + attr.array[indices[i] * 3 + 2] = attr.array[i * 3 + 2] - attr.array[i * 3] = newX; - attr.array[i * 3 + 1] = newY; - attr.array[i * 3 + 2] = newZ; + attr.array[i * 3] = newX + attr.array[i * 3 + 1] = newY + attr.array[i * 3 + 2] = newZ } - attr.needsUpdate = true; + attr.needsUpdate = true } - this.geometry.setDrawRange(0, sampleSize); + this.geometry.setDrawRange(0, sampleSize) } } diff --git a/src/Viewer/World/entities/segmentedPointCloud.js b/src/Viewer/World/entities/segmentedPointCloud.js index 31dcebc..6f575ab 100644 --- a/src/Viewer/World/entities/segmentedPointCloud.js +++ b/src/Viewer/World/entities/segmentedPointCloud.js @@ -63,13 +63,12 @@ export default class SegmentedPointCloud extends PointCloud { this.object.material.setValues({ vertexShader: vertexShader }) const attr = new THREE.BufferAttribute(this.colorsArray, 3) this.geometry.setAttribute('customColor', attr) - this.colorVectors = this.bufferToVector3(attr); + this.colorVectors = this.bufferToVector3(attr) this.colorVectors = this.bufferToVector3(this.geometry.getAttribute('customColor')) - } - setCloudResolution(sampleSize) { + setCloudResolution (sampleSize) { super.setCloudResolution(sampleSize) this.object.material.setValues({ vertexShader: vertexShader }) } diff --git a/src/Viewer/World/entities/workspace.js b/src/Viewer/World/entities/workspace.js index 32a781c..a90a40e 100644 --- a/src/Viewer/World/entities/workspace.js +++ b/src/Viewer/World/entities/workspace.js @@ -232,12 +232,11 @@ export default class Workspace { this.group ) - this.group.position.x = (workspace.x[1] + workspace.x[0]) / 2 this.group.position.y = (workspace.y[1] + workspace.y[0]) / 2 this.group.position.z = (workspace.z[1] + workspace.z[0]) / 2 + sizes.depth * 0.5 - - this.group.add(new THREE.AxesHelper(Math.min(sizes.width,sizes.height, sizes.width)/2)) + + this.group.add(new THREE.AxesHelper(Math.min(sizes.width, sizes.height, sizes.width) / 2)) if (parent) parent.add(this.group) } } diff --git a/src/Viewer/World/index.js b/src/Viewer/World/index.js index 99164db..0827912 100644 --- a/src/Viewer/World/index.js +++ b/src/Viewer/World/index.js @@ -311,7 +311,7 @@ export default function WorldComponent (props) { }, [mouse, world, measureClick] ) - + useEffect( () => { if (world) { @@ -416,17 +416,14 @@ export default function WorldComponent (props) { useEffect( () => { if (world && pointCloudGeometry) { - if(aabb.enforceReset) - { + if (aabb.enforceReset) { world.resetAxisAlignedBoundingBox(aabb) const bb = world.getAxisAlignedBoundingBox() - const merge = (...objects) => objects.reduce((acc, cur) => ({ ...acc, ...cur })); - setAABB(merge(aabb, bb, { enforceReset:false })); - } else - { + const merge = (...objects) => objects.reduce((acc, cur) => ({ ...acc, ...cur })) + setAABB(merge(aabb, bb, { enforceReset: false })) + } else { world.setAxisAlignedBoundingBox(aabb) } - } }, [aabb] diff --git a/src/Viewer/World/object.js b/src/Viewer/World/object.js index 1aaa581..2aef0b4 100644 --- a/src/Viewer/World/object.js +++ b/src/Viewer/World/object.js @@ -389,24 +389,20 @@ export default class World { this.pointCloud = new PointCloud(geometry, this.viewerObjects) } - setAxisAlignedBoundingBoxFromPointCloud() - { + setAxisAlignedBoundingBoxFromPointCloud () { this.aabb = new AABB(this.viewerObjects, this.pointCloud.geometry.boundingBox) } - setAxisAlignedBoundingBox(aabb) - { - if(!this.aabb) return; + setAxisAlignedBoundingBox (aabb) { + if (!this.aabb) return this.aabb.setBoundingBox(aabb) } - getAxisAlignedBoundingBox() - { + getAxisAlignedBoundingBox () { return this.aabb.getBoundingBox() } - resetAxisAlignedBoundingBox() - { + resetAxisAlignedBoundingBox () { this.aabb.resetBoundingBox() } @@ -417,7 +413,7 @@ export default class World { setSegmentedPointCloudGeometry (geometry, segmentation, uniqueLabels) { geometry.computeBoundingBox() - this.segmentedPointCloud = new SegmentedPointCloud(geometry,this.viewerObjects, + this.segmentedPointCloud = new SegmentedPointCloud(geometry, this.viewerObjects, segmentation, uniqueLabels) } @@ -465,20 +461,16 @@ export default class World { } } - setPointCloudSize(sampleSize) - { - if(this.pointCloud) - { + setPointCloudSize (sampleSize) { + if (this.pointCloud) { this.pointCloud.setCloudResolution(sampleSize) } - if(this.segmentedPointCloud) - { + if (this.segmentedPointCloud) { this.segmentedPointCloud.setCloudResolution(sampleSize) } - - if (this.pointCloudGroundTruth) - { + + if (this.pointCloudGroundTruth) { this.pointCloudGroundTruth.setCloudResolution(sampleSize) } } diff --git a/src/flow/interactions/reducer.js b/src/flow/interactions/reducer.js index 60275c7..72c1fda 100644 --- a/src/flow/interactions/reducer.js +++ b/src/flow/interactions/reducer.js @@ -43,164 +43,164 @@ export const initialState = { colors: { // Previous color values are left in comments - mesh: { rgb: "#96c0a7", a: 0.5 }, // a: 1 - pointCloud: { rgb: "#f8de96", a: 1 }, - pointCloudGroundTruth: { rgb: "#f8de96", a: 1 }, + mesh: { rgb: '#96c0a7', a: 0.5 }, // a: 1 + pointCloud: { rgb: '#f8de96', a: 1 }, + pointCloudGroundTruth: { rgb: '#f8de96', a: 1 }, segmentedPointCloud: [], - skeleton: { rgb: "#D0021B", a: 0.7 }, // { rgb: '#5ca001', a: 1 }, + skeleton: { rgb: '#D0021B', a: 0.7 }, // { rgb: '#5ca001', a: 1 }, organs: [], globalOrganColors: [ - { rgb: "#BD10E0", a: 0.5 }, - { rgb: "#E691F7", a: 0.5 }, + { rgb: '#BD10E0', a: 0.5 }, + { rgb: '#E691F7', a: 0.5 } ], // [{ rgb: '#3a4d45', a: 0.2 }, { rgb: '#00a960', a: 0.2 }], - background: {rgb: "#000000", a:1.0}, + background: { rgb: '#000000', a: 1.0 } }, pointCloudZoom: { - level: 2, + level: 2 }, pointCloudSize: { - sampleSize: 1000, + sampleSize: 1000 }, snapshot: { snapResolution: null, trueResolution: null, - image: null, + image: null }, ruler: { scaling: false, measuring: false, measure: 0, - scaleSet: false, + scaleSet: false }, aabb: { min: { x: 0, y: 0, - z: 0, + z: 0 }, max: { x: 0, y: 0, - z: 0, + z: 0 }, - enforceReset: false, + enforceReset: false }, reset3dViewFn: null, - reset2dViewFn: null, -}; + reset2dViewFn: null +} -export default function settingsReducer(state = initialState, action) { +export default function settingsReducer (state = initialState, action) { switch (action.type) { - case "RESET_INTERACTIONS": + case 'RESET_INTERACTIONS': return { ...state, - ...initialState, - }; - case "HOVER_CAMERA": + ...initialState + } + case 'HOVER_CAMERA': return { ...state, - hoveredCamera: action.value, - }; - case "SELECT_CAMERA": + hoveredCamera: action.value + } + case 'SELECT_CAMERA': return { ...state, - selectedCamera: action.value, - }; - case "HOVER_ANGLE": + selectedCamera: action.value + } + case 'HOVER_ANGLE': return { ...state, - hoveredAngle: action.value, - }; - case "SELECT_ANGLE": + hoveredAngle: action.value + } + case 'SELECT_ANGLE': return { ...state, selectedAngle: action.value, - selectedColor: null, - }; - case "SET_RESET_2D_VIEW": + selectedColor: null + } + case 'SET_RESET_2D_VIEW': return { ...state, - reset2dViewFn: action.value, - }; - case "SET_RESET_3D_VIEW": + reset2dViewFn: action.value + } + case 'SET_RESET_3D_VIEW': return { ...state, - reset3dViewFn: action.value, - }; - case "SET_COLORS": + reset3dViewFn: action.value + } + case 'SET_COLORS': return { ...state, - colors: action.value, - }; - case "RESTORE_DEFAULT_COLOR": + colors: action.value + } + case 'RESTORE_DEFAULT_COLOR': return { ...state, colors: { ...state.colors, - [action.value]: initialState.colors[action.value], - }, - }; - case "SET_SNAPSHOT": + [action.value]: initialState.colors[action.value] + } + } + case 'SET_SNAPSHOT': return { ...state, - snapshot: action.value, - }; - case "SET_ORGAN_INFO": + snapshot: action.value + } + case 'SET_ORGAN_INFO': return { ...state, - organInfo: action.value, - }; - case "SET_SELECTED_POINTS": + organInfo: action.value + } + case 'SET_SELECTED_POINTS': return { ...state, - selectedPoints: action.value, - }; - case "SET_CLICKED_POINT": + selectedPoints: action.value + } + case 'SET_CLICKED_POINT': return { ...state, - clickedPoint: action.value, - }; - case "SET_LABELS": + clickedPoint: action.value + } + case 'SET_LABELS': return { ...state, - labels: action.value, - }; - case "SET_SELECTED_LABEL": + labels: action.value + } + case 'SET_SELECTED_LABEL': return { ...state, - selectedLabel: action.value, - }; - case "SET_SELECTION_METHOD": + selectedLabel: action.value + } + case 'SET_SELECTION_METHOD': return { ...state, - selectionMethod: action.value, - }; - case "SET_RULER": + selectionMethod: action.value + } + case 'SET_RULER': return { ...state, - ruler: action.value, - }; - case "SET_POINT_CLOUD_ZOOM": + ruler: action.value + } + case 'SET_POINT_CLOUD_ZOOM': return { ...state, - pointCloudZoom: action.value, - }; - case "SET_POINT_CLOUD_SIZE": + pointCloudZoom: action.value + } + case 'SET_POINT_CLOUD_SIZE': return { ...state, - pointCloudSize: action.value, - }; - case "SET_AABB": + pointCloudSize: action.value + } + case 'SET_AABB': return { ...state, - aabb: action.value, - }; + aabb: action.value + } default: - return state; + return state } } diff --git a/src/flow/settings/reducer.js b/src/flow/settings/reducer.js index 298167e..1b0b003 100644 --- a/src/flow/settings/reducer.js +++ b/src/flow/settings/reducer.js @@ -36,7 +36,7 @@ export const initialState = { angles: false, cameras: false, segmentedPointCloud: false, - axisAlignedBoundingBox : false, + axisAlignedBoundingBox: false }, panels: { 'panels-angles': false, diff --git a/src/rd/UI/Slider/index.js b/src/rd/UI/Slider/index.js index 0bed405..d9a18bf 100644 --- a/src/rd/UI/Slider/index.js +++ b/src/rd/UI/Slider/index.js @@ -1,38 +1,32 @@ -import React from "react"; +import React from 'react' -export default class Slider extends React.Component -{ - constructor(props) - { - super(props); - this.state = { - value: 1, - callback: props.callback, - min : props.min && props.min > 0 ? props.min : 1, - max : props.min && props.max > 0 ? props.max : 1, - default : props.default && props.default > 0 ? props.default : 1, - step : props.step && props.step !== 0 ? props.step : 1 - }; - - - this.handleChange = this.handleChange.bind(this); +export default class Slider extends React.Component { + constructor (props) { + super(props) + this.state = { + value: 1, + callback: props.callback, + min: props.min && props.min > 0 ? props.min : 1, + max: props.min && props.max > 0 ? props.max : 1, + default: props.default && props.default > 0 ? props.default : 1, + step: props.step && props.step !== 0 ? props.step : 1 } + this.handleChange = this.handleChange.bind(this) + } - handleChange(event) - { - this.setState({value: event.target.value}); - this.state.callback(event.target.value); - } + handleChange (event) { + this.setState({ value: event.target.value }) + this.state.callback(event.target.value) + } - render() - { - return - } -} \ No newline at end of file + render () { + return + } +} From 604e0d52c511acaab67b6a9c6875c097d44644c8 Mon Sep 17 00:00:00 2001 From: Jonathan LEGRAND Date: Tue, 9 Apr 2024 20:40:49 +0200 Subject: [PATCH 2/9] Update Docz documentation title. --- doczrc.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doczrc.js b/doczrc.js index c2b2aea..2fc4e8a 100644 --- a/doczrc.js +++ b/doczrc.js @@ -1,6 +1,6 @@ export default { ignore: ['README.md'], - title: 'ROMI 3D Plant Visualizer', + title: 'ROMI Plant 3D Explorer', base: '/plant-3d-explorer/', hashRouter: true, menu: [ From 6c91c898c1b55b14edd2e921f72f1fdb385fcfff Mon Sep 17 00:00:00 2001 From: Jonathan LEGRAND Date: Tue, 9 Apr 2024 20:50:27 +0200 Subject: [PATCH 3/9] Undo breaking changes to `Dockerfile`. --- docker/Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index fc6ecf8..06fc91e 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,5 +1,5 @@ # Reworked original image based on https://mherman.org/blog/dockerizing-a-react-app/#docker -FROM node:12 +FROM node:10 LABEL maintainer="Jonathan LEGRAND " ARG API_URL='https://db.romi-project.eu' @@ -14,8 +14,8 @@ WORKDIR /app COPY package.json ./ COPY package-lock.json ./ -#RUN npm ci --only=production -RUN npm install +RUN npm ci --only=production +#RUN npm install RUN npm install react-scripts@3.4.1 -g COPY . ./ From 8973934a8ac3d083491443a63f4005c197fdc874 Mon Sep 17 00:00:00 2001 From: Jonathan LEGRAND Date: Tue, 9 Apr 2024 20:50:50 +0200 Subject: [PATCH 4/9] Improve `docker/run.sh`. --- docker/run.sh | 58 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 20 deletions(-) diff --git a/docker/run.sh b/docker/run.sh index 9d8944c..31f5cee 100755 --- a/docker/run.sh +++ b/docker/run.sh @@ -13,20 +13,24 @@ usage() { echo "DESCRIPTION:" echo " Run 'roboticsmicrofarms/plant-3d-explorer' container By default, start the container with the shared online database by ROMI: - $api_url + ${api_url} " echo "OPTIONS:" echo " -t, --tag - Docker image tag to use, default to '$vtag'." + Docker image tag to use, default to '${vtag}'." echo " --api_url - REACT API URL to use to retrieve dataset, default is '$api_url'. + REACT API URL to use to retrieve dataset, default is '${api_url}'. Set it to '127.0.0.0:5000' if you have a local plantdb instance running." echo " -c, --cmd Defines the command to run at container startup. By default it starts the Plant 3D Explorer listening to the given API URL." echo " -p, --port - Port to expose, default is '$port'." + Port to expose, default is '${port}'." + echo " -v, --volume + Volume mapping between host and container to mount a local directory in the container." \ + "Absolute paths are required and multiple use of this option is allowed." \ + "For example '-v /host/dir:/container/dir' makes the '/host/dir' directory accessible under '/container/dir' within the container." echo " -h, --help Output a usage message and exit." } @@ -49,6 +53,14 @@ while [ "$1" != "" ]; do shift port=$1 ;; + -v | --volume) + shift + if [ "${mount_option}" == "" ]; then + mount_option="-v $1" + else + mount_option="${mount_option} -v $1" # append + fi + ;; -h | --help) usage exit @@ -61,26 +73,32 @@ while [ "$1" != "" ]; do shift done +# Check if we have a TTY or not +if [ -t 1 ]; then + USE_TTY="-t" +else + USE_TTY="" +fi + # Docker commands based on : https://mherman.org/blog/dockerizing-a-react-app/#docker -if [ "$cmd" = "" ]; then - # Start in interactive mode: - docker run \ - -it \ - --rm \ - -p $port:$port \ - -e CHOKIDAR_USEPOLLING="true" \ - -e REACT_APP_API_URL="$api_url" \ - roboticsmicrofarms/plant-3d-explorer:$vtag +if [ "${cmd}" = "" ]; then + # Start in interactive mode, using the `-i` flag (load `~/.bashrc`). + docker run --rm ${mount_option} \ + --env CHOKIDAR_USEPOLLING="true" \ + --env REACT_APP_API_URL="${api_url}" \ + -p ${port}:${port} \ + -i ${USE_TTY} \ + roboticsmicrofarms/plant-3d-explorer:${vtag} # --rm : Remove container after closing # -v ${PWD}:/app : Mount the app folder # -v /app/node_modules : Mount the node modules # -e CHOKIDAR_USEPOLLING="true" : Allow hot-reload else - # Start in non-interactive mode (run the command): - docker run \ - --rm \ - --env REACT_APP_API_URL="$api_url" \ - -p $port:$port \ - roboticsmicrofarms/plant-3d-explorer:$vtag \ - bash -c "$cmd" + # Start in interactive mode, using the `-i` flag (load `~/.bashrc`). + docker run --rm ${mount_option} \ + --env REACT_APP_API_URL="${api_url}" \ + -p ${port}:${port} \ + -i ${USE_TTY} \ + roboticsmicrofarms/plant-3d-explorer:${vtag} \ + bash -c "${cmd}" fi From 5032d73a2f4d58eb0ec47208f179d57b80ba7500 Mon Sep 17 00:00:00 2001 From: Jonathan LEGRAND Date: Tue, 9 Apr 2024 20:51:11 +0200 Subject: [PATCH 5/9] Fix typo. --- src/Viewer/World/entities/segmentedPointCloud.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Viewer/World/entities/segmentedPointCloud.js b/src/Viewer/World/entities/segmentedPointCloud.js index 6f575ab..6dfd8ef 100644 --- a/src/Viewer/World/entities/segmentedPointCloud.js +++ b/src/Viewer/World/entities/segmentedPointCloud.js @@ -189,5 +189,5 @@ export default class SegmentedPointCloud extends PointCloud { this.geometry.removeAttribute('customColor') this.geometry.addAttribute('customColor', new THREE.BufferAttribute(this.colorsArray, 3)) - }1 + } } From 50da2b161fef6dfa8c04bbb73dfdd5ebaa72cec9 Mon Sep 17 00:00:00 2001 From: Jonathan LEGRAND Date: Tue, 9 Apr 2024 20:54:08 +0200 Subject: [PATCH 6/9] Change outdated npm package name. --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index edf73b2..d0868eb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "sony_visualiseur-plantes-3d", + "name": "plant-3d-explorer", "version": "0.1.0", "lockfileVersion": 1, "requires": true, diff --git a/package.json b/package.json index a3a65d5..36e8535 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "sony_visualiseur-plantes-3d", + "name": "plant-3d-explorer", "version": "0.1.0", "private": true, "homepage": "https://db.romi-project.eu/viz/", From 2f765c1162c57eb82642ca3dcb4613a7350f2dfd Mon Sep 17 00:00:00 2001 From: Jonathan LEGRAND Date: Tue, 9 Apr 2024 20:54:56 +0200 Subject: [PATCH 7/9] Update gitlab `pages` CI job. --- .github/workflows/pages.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 345a330..a99c70a 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -9,11 +9,15 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - name: Checkout + uses: actions/checkout@v2 with: persist-credentials: false - name: Build + uses: actions/setup-node@v4 + with: + node-version: '10.x' run: npm ci && npm run docz:build - name: Deploy From 1d75809e1cc77751388b2f92b0999fc6d7792506 Mon Sep 17 00:00:00 2001 From: Jonathan LEGRAND Date: Tue, 9 Apr 2024 20:57:28 +0200 Subject: [PATCH 8/9] Update gitlab `pages` CI job. --- .github/workflows/pages.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index a99c70a..fb73539 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -18,7 +18,8 @@ jobs: uses: actions/setup-node@v4 with: node-version: '10.x' - run: npm ci && npm run docz:build + - run: npm ci + - run: npm run docz:build - name: Deploy uses: peaceiris/actions-gh-pages@v3 From cb54cfebcd7ecfb5cc025b5276f99eadce609b99 Mon Sep 17 00:00:00 2001 From: Jonathan LEGRAND Date: Tue, 9 Apr 2024 20:58:28 +0200 Subject: [PATCH 9/9] Update README. --- README.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index da5ef3c..7d140d9 100755 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ sudo apt-get install -y nodejs For other distro look [here](https://github.com/nodesource/distributions/blob/master/README.md) or [here](https://nodejs.org/en/download/) for non linux distro. -To make sure everything works fine, your version of nodejs must be >= 10, and your version of npm must be >= 6. +To make sure everything works fine, your version of Node.js must be >= 10, and your version of npm must be >= 6. To test it: ```shell @@ -198,17 +198,17 @@ To use local builds for development or debugging purposes: ## Technical documentation -### view +### View https://romi.github.io/plant-3d-explorer/ -### contribute +### Contribute -The documentation of this package is done by [docz](https://www.docz.site/). +The documentation of this package is done by [docz](https://docz-v1.surge.sh/). To install it, and its dependencies, do: ```bash -npm install docz react react-dom +npm install docz@1.3.2 docz-theme-default ``` Then: @@ -217,4 +217,10 @@ Then: npm run docz:dev ``` -If you experience any difficulty with `docz`, head over [here](https://www.docz.site/docs/getting-started). +To build it within a container: +```shell +./docker/run.sh -v $(pwd)/.docz:/app/.docz \ + -c "umask 0002 && npm install docz@1.3.2 docz-theme-default && npm run docz:build" +``` + +If you experience any difficulty with `docz`, head over [here](https://docz-v1.surge.sh/).