potree icon indicating copy to clipboard operation
potree copied to clipboard

How to integrate Potree into react or VueJS ?

Open Entropy-9973 opened this issue 4 years ago • 27 comments

Have anyone tried to do this ?

are there are any guidlines or tips as this looks like a very challenging task

Should i simply run two servers in the background with an Iframe in a react component ?

Entropy-9973 avatar Nov 20 '20 13:11 Entropy-9973

It's possible, but it requires some time and compromises. For example you can to build your own bundle (eg. with Webpack) with all packages required to launch Potree (like Three, Tween, D3, etc) and then call Potree as ref for DOM element. After Potree launched all functions are available in global scope.

Your proposition with iframe also should work, but communication with rest of application will be more difficult.

pewuel avatar Nov 24 '20 18:11 pewuel

I am currently developing a react app displaying Potree pointclouds. Afaik it's not possible to bundle any Potree code using webpack given its non-explicit imports (a major technical debt that will need to be repayed someday in the future...).

My constraints were:

  1. A working react app allowing to interact with Potree pointclouds
  2. ...that compiles without warnings in react strict mode
  3. ...without any modification of Potree source code to ensure future compatibility
  4. ...while avoiding duplicate imports for Potree and for the react app

After a bit of hacking around, here is my solution, starting from a create-react-app project. It'd be great to have proper ES6 Potree source code or a npm Potree package. Anyway, Potree is a great open-source project, so I'm happy with whatever we get ;-)

Add the potree libs as <script> tags in public/index.html

  1. Create the public/potree_libs/ folder and copy all the js libraries used by Potree.
  2. Add them as <script> tags inside react's template file public/index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="React+Potree"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <title>React+Potree</title>

    <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css"
    integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
    crossorigin=""/>

    <script src="potree_libs/jquery/jquery-3.1.1.min.js"></script>
    <script src="potree_libs/spectrum/spectrum.js"></script>
    <script src="potree_libs/jquery-ui/jquery-ui.min.js"></script>
    <script src="potree_libs/three.js/build/three.js"></script>
    <script src="potree_libs/three.interaction.0.2.3.js"></script>
    <script src="potree_libs/other/BinaryHeap.js"></script>
    <script src="potree_libs/tween/tween.min.js"></script>
    <script src="potree_libs/d3/d3.js"></script>
    <script src="potree_libs/proj4/proj4.js"></script>
    <script src="potree_libs/openlayers3/ol.js"></script>
    <script src="potree_libs/i18next/i18next.js"></script>
    <script src="potree_libs/jstree/jstree.js"></script>
    <script src="potree_libs/potree/potree.js"></script>
    <script src="potree_libs/plasio/js/laslaz.js"></script>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="react-root"></div>
  </body>
</html>

Import Potree and create Viewer in React

  1. whenever I need Potree, or one of its dependency library, I do a dirty import using const libname = window.libname. In the following snippet, you can see I am importing Potree, three.js and tween.js (even though I am not using three.js and tween.js in this simple example).
  2. Initialize Potree Viewer inside componentDidMount()
  3. If needed, update Potree in componentDidUpdate()

Here is a simple react component displaying a pointcloud:

import React from 'react';

// import vanillaJS Potree libs, /!\ would be best with proper ES6 import
const Potree = window.Potree
const THREE = window.THREE
const TWEEN = window.TWEEN

export default class PointcloudNavigator  extends React.Component{
    constructor(props){
        super(props)
        this.potreeContainerDiv = React.createRef();
    }

    
    render(){
        return (
            <div  id="potree-root">
                <div  ref={this.potreeContainerDiv} className={"potree_container "}>
                    <div id="potree_render_area"></div>
                </div>
                
            </div>
        )
    }

    componentDidMount(){
        // initialize Potree viewer
        const viewerElem = this.potreeContainerDiv.current
        this.viewer = new Potree.Viewer(viewerElem);

		viewer.setEDLEnabled(true);
		viewer.setFOV(60);
		viewer.setPointBudget(1*1000*1000);
		viewer.setClipTask(Potree.ClipTask.SHOW_INSIDE);
		viewer.loadSettingsFromURL();

		viewer.setControls( viewer.earthControls ) 
		
		// Load and add point cloud to scene
		let url = "./pointcloud/metadata.json" // do not forget to put your pointcloud data in the public/pointcloud/ folder
		Potree.loadPointCloud(url).then(e => {
			let scene = viewer.scene;
			let pointcloud = e.pointcloud;
			let material = pointcloud.material;

			material.activeAttributeName = "rgba";
			material.minSize = 2;
			material.pointSizeType = Potree.PointSizeType.FIXED

			viewer.scene.addPointCloud(pointcloud);

			viewer.fitToScreen();
		}, e => console.err("ERROR: ", e));
    }

    componentDidUpdate(){
        // If you want to update Potree View/other element upon render(), put it here
    }
}

dddpt avatar Dec 21 '20 14:12 dddpt

(a major technical debt that will need to be repayed someday in the future...).

It is, but at this point it won't change for Potree 1.x anymore since I'll shift focus to Potree 2.0. Potree 2.0 will be a ground-up rewrite that fully relies on ES6 imports, but it still won't use webpack or gulp due to the build times and the insane dependency trees. Idealy, it won't use any build systems at all, at least none that add more than a single-digit amount of dependencies to the node_modules folder.

m-schuetz avatar Dec 21 '20 14:12 m-schuetz

Great! Thanks for the good news. Looking forward to Potree 2! 🥳🥳

dddpt avatar Dec 21 '20 14:12 dddpt

@m-schuetz Do you have any ETA on approx. timelines for v2? I'm sure it's an absolute ton of work, so not trying to put pressure, more just curious.

321ckatz123 avatar Dec 22 '20 16:12 321ckatz123

No ETA or roadmap yet, but the idea is to start working in January, publish prototypes throughout 2021, first early one perhaps around end of February. Note that this is a rewrite and as such, the first prototypes are going to be very barebones and centered mostly around the rendering aspect rather than functionality. I'd expect a full 2.0 release earliest at the end of 2021, but perhaps later, depending on WebGPU. WebGPU also doesn't have a clearly scheduled release date but as far as I've understood, first regularly distributed prototypes (i.e. distributed in Chrome rather than Canary, but still behind a flag) are also expected in the first half of 2021.

potree avatar Dec 22 '20 17:12 potree

@potree @m-schuetz I'm interested in the renderer rebuilt decisions if you can share something about it. Are you going to work on your own WebGPU renderer? or do you plan to use the experimental WebGPU renderer from three.js? If the former will that mean that potree 2.0 will stop supporting three.js? Thanks!

fernandojsg avatar Dec 22 '20 21:12 fernandojsg

@dddpt I tried your example of running potree in React. After loading all of the libraries and running the application, It just sits and waits with no errors and the "[HMR] Waiting for update signal from WDS..." message in the console window.

Have you seen this before?

matt-miracad avatar Jun 07 '21 17:06 matt-miracad

@Hamza-Ghizaoui, at work my team and I are building a points cloud viewer app for the company we work for, and I was able to integrate the Potree viewer into React (it took me a couple of days). When I joined the company we already had an initial app that was including the viewer, but it wasn't working, so what I did was starting fresh with an "empty" app (create-react-app), then I included the Potree code you get on GitHub and after a few adjustments it worked. After that I was even able to change the viewer from a class component to a function component, as well as having it to source the Octree files from an Azure blob storage account with a loop.

I will have to double check with my manager whether I can share the code here, just because I wouldn't want to breach the company intellectual property policies and get in trouble. :)

My comment was just to motivate you and say that it can definitely be done, and if I've done it (being a newbie with React), you can it too! :)

worlderland avatar Oct 12 '21 07:10 worlderland

@Hamza-Ghizaoui I will have to double check with my manager whether I can share the code here, just because I wouldn't want to breach the company intellectual property policies and get in trouble. :)

My comment was just to motivate you and say that it can definitely be done, and if I've done it (being a newbie with React), you can it too! :)

I'm motivated :)
Are you going to be able to share? I'm on the edge of my seat biting my fingernails LOL!

Thanks, either way...

aqf01011990 avatar Oct 21 '21 18:10 aqf01011990

@aqf01011990 and @Hamza-Ghizaouia I double checked with management and I was allowed to share my test code; please find it here: https://github.com/worlderland/PotreeViewerReact

Just npm install, then go into components/PotreeViewer.jsand on line 58 insert the URL where your point cloud is hosted, and then run npm start. It'll show you the cloud.

Unfortunately it's very basic, quick and easy to set up (no tools/sidebar, just the viewer as it's what I needed to test), but it leaves you lots to play with. :) From here I was able to convert the class component into a function component (followed a procedure through stackoverflows if I remember correctly) and adapted it to what we needed.

Hope this helped you and let me know you it went. :)

worlderland avatar Oct 22 '21 02:10 worlderland

@worlderland Thank you!

smcavoy12 avatar Oct 22 '21 02:10 smcavoy12

@worlderland

Hope this helped you and let me know you it went. :)

Thank you very much!! I'll let you know

aqf01011990 avatar Oct 22 '21 20:10 aqf01011990

@worlderland

Hope this helped you and let me know you it went. :)

Thank you very much!! I'll let you know

aqf01011990 avatar Oct 22 '21 20:10 aqf01011990

Sobres para los que siguen buscando https://github.com/AlvaroDuron/react-potree

beat-ARDA avatar Jan 06 '22 22:01 beat-ARDA

So I used previous examples in this thread and had lots of css issues. I was adding the viewer in tabbed panels My fix was creating an html template with a variable added in as a string for the pointcloud reference. Then I loaded that up as the srcDoc of an iframe. ..Just figured I'd share

rickycohen88 avatar May 24 '22 16:05 rickycohen88

@worlderland The URL of point cloud which we will use, does that file should be any specific format like (.ply, e57 or .json), can you show how you are storing in point cloud and so that help a lot thanks.

srikanth14526 avatar Jun 08 '22 10:06 srikanth14526

@worlderland The URL of point cloud which we will use, does that file should be any specific format like (.ply, e57 or .json), can you show how you are storing in point cloud and so that help a lot thanks.

@srikanth14526 to my knowledge in order to be able to display 3D models in Potree you need 3 files: metadata.json (or any name, as long as is .json) hierarchy.bin octree.bin (there's a 4th one but it's only a log) and you always call the .json file in your URL.

You get these files outputted from the Potree Converter (https://github.com/potree/PotreeConverter) where you'll need to feed in .las/.laz file/s.

Once you got the above mentioned files, you can store them anywhere you like, then, you look for the function Potree.loadPointCloud in your code (for example, it's on line 61 of the file viewer.html, inside the folder "examples") and as first parameter you specify the URL where all 3 files are, but calling the .json like so: Potree.loadPointCloud("../pointclouds/vol_total/cloud.js", ...rest of parameters).

Hope this helps.

worlderland avatar Jun 28 '22 08:06 worlderland

@worlderland is it possible to add onClick events on model, and use that to add annotations ?

Loads of gratitude, for sample react app, i was stuck for some days, before i found this :)

ajitStephen avatar Oct 27 '22 13:10 ajitStephen

vol_total/cloud.js

hey @worlderland I am getting this error below while using your repo what do you think ?

× SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON xhr.onreadystatechange ../../src/loader/POCLoader.js:130:21

I would suggest you be through, your model is good. try verifying with different tools.

ajitStephen avatar Nov 21 '22 04:11 ajitStephen

@worlderland I have dataset that is cloud hosted. How should I proceed with adding URL. I see that your code only loads the 3d model if it is in public folder.

Hi @bestimus , please refer to my comment above: https://github.com/potree/potree/issues/939#issuecomment-1168425166.

Look for the Potree.loadPointCloud() function and replace the url string there with yours. For example, we use Azure, so I would use the url that points to a blob storage folder where we store the Potree files. You'll have to make sure the CORS are set correctly and all the general security settings to access the files.

worlderland avatar Nov 22 '22 00:11 worlderland

@worlderland is it possible to add onClick events on model, and use that to add annotations ?

Loads of gratitude, for sample react app, i was stuck for some days, before i found this :)

Hi @ajitStephen , could you kindly be more specific please? :) I don't entirely understand the question.

worlderland avatar Nov 22 '22 00:11 worlderland

Can someone suggest how to integrate the potree side bar ?

kiranjoshy123 avatar Aug 03 '23 13:08 kiranjoshy123

Can someone suggest how to integrate the potree side bar ?

I ended up making my use cases with three.js. for glb & pcd models. It is way simpler than trying to things with potree.

ajitStephen avatar Aug 07 '23 07:08 ajitStephen

This solution worked for me. Thanks.. But when I build the react application and run with command 'server -s build', the Potree keeps loading the data, but it never loads. Anyone has any clue ?

kiranjoshy123 avatar Sep 22 '23 22:09 kiranjoshy123

Call useCanvas at the top of your app. Then useEngine anywhere else. Works with react with no compromise.

const EngineContext = createContext(null);

const Canvas = styled.div`
  position: absolute;
  bottom: 0px;
  top: ${({topValue})=>topValue}px;
  left: 0px;
  right: 0px;
  z-index: 0;
  canvas {
    outline: none;
  }
`;

export function EngineProvider({children}) {
    //need to use ref otherwise potree throws an error due to jquery
    const ref = useRef();

    const canvas = useMemo(()=><Canvas ref={ref} topValue={0} />, [])
    const [engine, setEngine] = useState();

    function useCanvas() {
        disposeEngine();
        return canvas;
    }

    function initEngine() {
        disposeEngine();
        setEngine(new window.Potree.Viewer(ref.current));
    }

    function disposeEngine() {
        //engine && engine.dispose();
    }

    function useEngine() {
        return engine;
    }

    return (
        <EngineContext.Provider
            value={{
                useEngine,
                useCanvas,
                initEngine,
                disposeEngine,
            }}
        >
            {children}
        </EngineContext.Provider>
    );
}

export function useCanvas() {
    const canvas = useContext(EngineContext).useCanvas();
    const {initEngine, disposeEngine} = useContext(EngineContext);
    
    useEffect(()=>{
        initEngine();
        return ()=>disposeEngine();
    },[]);

    return canvas;
}

export function useEngine() {
    return useContext(EngineContext).useEngine();
}

lewibs-Powern avatar Oct 05 '23 20:10 lewibs-Powern

@worlderland I have dataset that is cloud hosted. How should I proceed with adding URL. I see that your code only loads the 3d model if it is in public folder.

Hi @bestimus , please refer to my comment above: #939 (comment).

Look for the Potree.loadPointCloud() function and replace the url string there with yours. For example, we use Azure, so I would use the url that points to a blob storage folder where we store the Potree files. You'll have to make sure the CORS are set correctly and all the general security settings to access the files.

How can we load these files from aws s3 storage. Because for S3 storage, there is not concept of folder. We only got presign url's for each file. So how can we load pointcloud from s3 storage? Please guide on this!

im-hamza-dev avatar Jun 20 '24 05:06 im-hamza-dev