jeromeetienne / AR.js

Efficient Augmented Reality for the Web - 60fps on mobile!
MIT License
15.78k stars 2.22k forks source link

Integrations with JS Frameworks #537

Closed nicolocarpignoli closed 4 years ago

nicolocarpignoli commented 5 years ago

Hi everybody, I think it could be very useful to have on the Readme a section for AR.js state-of-the-art about integrations with JS frameworks.

I see, for example in here https://github.com/jeromeetienne/AR.js/issues/493#issuecomment-490303718, that some of you already have achieved that with React. It's great!

Can we collect all of your experiences, and make a simple PR to update the Readme with these informations? Even a simple list of links to working examples/snippets/small projects that integrate AR.js with some framework, may it be Vue, Angular, React, Preact, etc.

Thanks!

kalwalt commented 5 years ago

This is a good Idea, i will do for the React examples!

nicolocarpignoli commented 5 years ago

For React, there is this discussion going on: https://github.com/jeromeetienne/AR.js/issues/493 we can continue here

JustinStoddard commented 5 years ago

I was told to post this here ✌️

Describe The Issue When I'm not in full screen mode the default yellow box in the starter code isn't showing up as expected. I think this is the reason. <canvas class="a-canvas" data-aframe-canvas="true" width="2102" height="0"></canvas> For some reason the height of the canvas element has defaulted to 0. But when I enter full screen mode through the VR goggles button it changes to: <canvas class="a-canvas" data-aframe-canvas="true" width="2399" height="1799"></canvas>

To Reproduce Visit "https://www.thisjustin.tech/webar" in chrome, then inspect the VR Mode button. Then navigate to the elements tab inside your DevTools and find the element. There you can see the inline styles. Test what it looks like in Full Screen and Not in Full screen to see what i'm talking about. Then if your curious navigate out of fullscreen mode, remove the "position: absolute" css tag from the element while holding up a "Hiro" marker to the camera. You'll see the yellow box float down the screen.

Expected behavior To behave as it does on the codepen demo. https://codepen.io/nicolocarpignoli/pen/vMBgob

Additional context Here are the CDN tags i'm using provided in the getting started code. <script src="https://aframe.io/releases/0.9.1/aframe.min.js"></script> <script src="https://raw.githack.com/jeromeetienne/AR.js/1.7.1/aframe/build/aframe-ar.js"></script> If you would like to see my Repo please visit "https://github.com/JustinStoddard/justin-s-com" I am using React v16.8.0 and a Semantic-UI-React v0.82.3, maybe the Styled Component Library is messing with the height? Anyway, I've been scratching my head around this for a couple hours. So any help helps. Good luck!

(EDIT 6/23/19): @nicolocarpignoli I get an error in the console when ever WebAr is initialized: [Deprecation] document.registerElement is deprecated and will be removed in M73, around March 2019. Please use window.customElements.define instead. See https://www.chromestatus.com/features/4642138092470272 for more details. It seems maybe this is why its happening. Ar.js currently uses document.registerElement to project an object or element into an AR environment. Well now that's been made completely obsolete. So we need to use window.customElements.define instead.

nicolocarpignoli commented 5 years ago

@JustinStoddard honestly, I found document.registerElement only on demos or examples, can you point me where you see that if you think it is that to causing problems?

image

zkyf commented 5 years ago

I'm using Ant Design and my current solution is to just avoid using Node.js and use the compiled production js scripts with jsx scripts for react.

A simple example:

<html>
    <script src="./js/aframe.min.js"></script>
    <script src="./js/aframe-ar.js"></script>
    <script src="https://cdn.bootcss.com/react/16.8.6/umd/react.production.min.js"></script>
    <script src="https://cdn.bootcss.com/react-dom/16.8.6/umd/react-dom.production.min.js"></script>
    <script src="https://unpkg.com/babel-standalone@6.26.0/babel.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/antd/3.19.8/antd.css" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/antd/3.19.8/antd.js"></script>
    </style>
    <body style='margin : 0px; overflow: hidden;' class='lock-screen'>
        <div>
            <a-scene embedded artoolkit='sourceType: webcam;' arjs="trackingMethod: best; debugUIEnabled: false;">
                <a-marker preset='hiro'>
                    <a-cylinder position="0 0 0" color="#F55" radius="1" scale="1 1 1"></a-cylinder>
                </a-marker>
                <a-entity camera></a-entity>
            </a-scene>
        </div>
        <div id="header_wrapper" style="width:100%; position:absolute; top:0px;"></div>
    </body>
    <script type="text/babel">
    ReactDOM.render(
        <antd.PageHeader onBack={() => {window.location='/route'}} title="AR app" subTitle="header"></antd.PageHeader>,
        document.getElementById('header_wrapper'));
    </script>
</html>

Here I have downloaded Ar.js and AFrame to local paths for better performance.

Notice that the react code you use should be put in <script> tag with type="text/babel" since jsx is not the standard js.

Result: IMG_4366

michael-small commented 5 years ago

@JustinStoddard honestly, I found document.registerElement only on demos or examples, can you point me where you see that if you think it is that to causing problems?

@nicolocarpignoli I get the same error in chrome from a-register-element.js:69 when importing aframe in a script tag from https://aframe.io/releases/0.9.1/aframe.min.js.

I am trying to use AR.js in Angular 8, but this problem is consistent in Chrome even when I'm just not using Angular in a vanilla html/js context. I have my own questions/observations about Angular 8 for this thread that my coworkers and I mean to get around to formulating, but I thought I would just mention that the document.registerElement problem is present across frameworks and vanilla AR.js examples. That said, that deprecation warning is present in both working and non-working AR.js implementations that our team has created regardless of using Angular or not.

Note: The deprecation of document.registerElement is documented in an aframe issue:

dmarcos commented on Dec 17, 2018 It’s ok. We will eventually move to the new custom elements API but we have a polyfill / fallback at the moment on top of Mutation Observers. A-Frame won’t break.

image

EDIT: The linked React thread was the inspiration my team needed for a breakthrough to get Angular working with AR.js. Once we oil out the details we mean to lay out a guide on what we had to do to make Angular work and post it in this thread.

michael-small commented 5 years ago

A quick and dirty Angular2+ implementation guide for AR.js as requested by @nicolocarpignoli in another thread.

@michael-small Hi, can you share with us the angular doc to run ar.js app on the thread linked by you?

To be honest I misspoke a bit because technically my team's Angular doc isn't quite ready. However, I will give a quick and dirty overview of our Angular advice. When our doc is fully fleshed out we will link it here and/or edit this comment. We are figuring this out and optimizing as we go, so this is no be-all-end-all solution and would gladly take input.

Apologies for the length and formatting, I was a bit rushed.

Solution # 1 (simpler)

Before anything with AFrame syntax can be used in Angular, CUSTOM_ELEMENTS_SCHEMA must be set in the NgModule directive and the two AR.js related script tags must be set in index.html. See this comment by @jsebrech on how to do that from the start on an Angular project with AR.js to the first run of it. Note: the scripts are outdated so make sure to use more current ones.

The example app.component.html from the link above should work out of the box on any supported browser with a Hiro marker. That said, our team uses barcode markers that show a-image's. My team's big issues with Angular and AR.js was with barcodes working in Chrome. Barcodes showed up using example code like below in all browsers except Chrome. More on that below.

This should be all that is necessary for Angular and AR.js to get along, in Chrome, on supported OS's, using barcode markers.

Our component is app.component with the selector app-root, so the HTML of index.html and app.component.html should look like this:

index.html

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>ArSimulation</title>
  <base href="/">

  <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no,minimum-scale=1,maximum-scale=1"/> <!--https://github.com/jeromeetienne/AR.js/issues/541#issue-457792891-->
  <link rel="icon" type="image/x-icon" href="favicon.ico">
  <link rel="manifest" href="manifest.webmanifest">
  <meta name="theme-color" content="#1976d2">
  <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" rel="stylesheet">
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> 

  <!-- AR.js related Script Imports -->
  <script src="https://aframe.io/releases/0.9.1/aframe.min.js"></script>
  <script src="https://cdn.rawgit.com/jeromeetienne/AR.js/1.7.2/aframe/build/aframe-ar.js"></script>

</head>

<body class="mdc-typography">

  <!-- Component selector on app.component -->
  <app-root></app-root>

  <noscript>Please enable JavaScript to continue using this application.</noscript>
</body>
</html>

app.component.html

<a-scene embedded arjs='sourceType: webcam; debugUIEnabled: false; detectionMode: mono_and_matrix; matrixCodeType: 3x3;'>
    <a-marker type='barcode' value='2'>
                <!-- Replace with your own image from the assets folder or linked from an HTTPS source  -->
        <a-image src="assets/image.png" position="0 0 0" rotation="-90 0 0" scale="1 1 1"></a-image>
    </a-marker>
    <a-entity camera></a-entity>
</a-scene> 

With this configuration, barcode images seemingly should work by the syntax conventions of AR.js, but is a little more complicated. As @fega mentions and @kalwalt implemented in React, but converted to Angular, for AR.js to work in an Angular component there needs to be a delay in the component being instantiated (in Chrome, other browsers like Firefox or Edge didn't need this solution).

This can be achieved by just a few lines in the component's typescript file and html file.

app.component.ts

export class AppComponent implements OnInit {

  //tied to the *ngIf="showContent" in the component's html
  public showContent: boolean = false;

  public ngOnInit() {
    //This delays the content of the component from showing until aframe and aframe-ar.js load
    //NOTE: This arbitrary 1 second wait may be too long, or worse, too short. See end for more info.

    setTimeout(()=>this.showContent=true, 1000); 

    //Thanks to Valikhan Akhmedov, Oct 4 '16 at 12:22 @ https://stackoverflow.com/a/39852249/8273171
    //This move was inspired by kawalt's react-aframe-ar-test's index.js @ https://github.com/kalwalt/react-aframe-ar-test/blob/master/src/index.js
    //which was inspired by fega @ https://github.com/jeromeetienne/AR.js/issues/493#issuecomment-490303718
  }

app.component.html

<!-- Notice the *ngIf in the a-scene. The component will not show up until showContent is set true in ngOnInit -->

<a-scene embedded arjs='sourceType: webcam; debugUIEnabled: false; detectionMode: 
mono_and_matrix; matrixCodeType: 3x3;' *ngIf="showContent">
    <a-marker type='barcode' value='2'>
        <a-image src="assets/image.png" position="0 0 0" rotation="-90 0 0" scale="1 1 1"></a-image>
    </a-marker>
    <a-entity camera></a-entity>
</a-scene> 

And for our team implementing AR.js with Angular, that was all we needed.

Solution # 2 (refined Solution # 1)

However, there are a few caveats. As I mentioned about the showContent 1 second delay, delays with a static time aren't reliable as that delay is either too much or possibly not enough due to potential network or async issues.

Our solution is to dynamically load aframe and aframe-ar.js using DynamicScriptLoaderService.ts by Zain Zafar in his article "Angular: Load External JavaScript File Dynamically". First of all, remove the two script tags related to AR.js from index.html. Then add DynamicScriptLoaderService.ts to your project by making it a provider in app.module.ts's @NgModule and import the service in app.component.ts. Our ScriptStore is:

export const ScriptStore: Scripts[] = [
  { name: 'aframe', src: "https://aframe.io/releases/0.9.1/aframe.min.js" },
  { name: 'arjs', src: "https://cdn.rawgit.com/jeromeetienne/AR.js/1.7.2/aframe/build/aframe-ar.js" }
];

Back in your app.component.ts, add the following method loadScripts() and call it on ngOnInit():

app.component.ts

  ngOnInit() {
    this.loadScripts();
  }

  private loadScripts() {
    this.dynamicScriptLoader.load('aframe','arjs').then(data => {
      this.showContent=true;
    }).catch(error => console.log(error));
  }

We're almost there. The last needed bit is to add an event listener in ngOnInit.

Once everything is said and done, your app.component.ts should look like this:

app.component.ts

import { Component, OnInit } from '@angular/core';
import { DynamicScriptLoaderService } from '.../path_to_service/DynamicScriptLoaderService'  

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})

export class AppComponent implements OnInit {

  public showContent: boolean = false;

  constructor(private dynamicScriptLoader: DynamicScriptLoaderService) {}

  ngOnInit() {
    this.loadScripts();

    window.addEventListener('load', (event) => {  //Thanks to this article: https://www.kirupa.com/html5/running_your_code_at_the_right_time.htm
    });
  }

  private loadScripts() {
    this.dynamicScriptLoader.load('aframe','arjs').then(data => {
      this.showContent=true;
    }).catch(error => console.log(error));
  }
}

Now AR.js and Aframe will be loaded in dynamically when it is ready.

This should be all that is necessary for Angular and AR.js to get along, in Chrome, on supported OS's, using barcode markers. As I said earlier, my team intends to refine and condense this info into a proper documentation document at a later date when we have more figured out.

PS: If you want to set markers's properties using our setup, check out this issue by @HeinPauwelyn. Our team uses the typescript solution inside of the window.addEventListener.

FelixStumvoll commented 5 years ago

I'm currently working on a Angular Application with AR.js, the only thing i had to do to get it working was to include the two scripts in the header and add CUSTOM_ELEMENTS_SCHEMA in app.module.ts. No dynamic script loading needed.

Alternativly you could also install the npm dependencies and add the javascript files them to the scripts section in angular.json like this: "scripts": ["node_modules/aframe/dist/aframe-master.js", "node_modules/ar.js/aframe/build/aframe-ar.js"]

denisstasyev commented 4 years ago

Hello, everyone! It looks like I have found one more way how to implement AR.js into React to use it as Component. Here you can check my attempt.

roberttolton commented 4 years ago

Has anyone has luck integrating this with VueJS? I've found that if <a-scene> is not a root element underneath <body>, then nothing works.

Therefore it's impossible to have AR on just one route, because the <a-scene> element will be present all the time in the app.

denisstasyev commented 4 years ago

Has anyone has luck integrating this with VueJS? I've found that if <a-scene> is not a root element underneath <body>, then nothing works.

Therefore it's impossible to have AR on just one route, because the <a-scene> element will be present all the time in the app.

That’s true. In my own experience with React I’ve switched from A-Frame to Three.js. It’s more complicated, but in my case it was the only way how to fix some troubles with styles.

You can check my own experience here https://github.com/denisstasyev/E-Gifts/blob/dev/frontend/src/containers/Outdated/ViewGift/ViewGift.js

It includes ARViewer - this is a core thing for AR.js to work. I’m going to create separate repository soon to simplify and share this my experience.

jeanmachuca commented 4 years ago

Hello everyone here! have any of you tried to integrate AR.js using QCObjects ? I’m preparing a good article to explain how to do it in simple steps. I’ll let you know soon... cheers

nico-martin commented 4 years ago

@roberttolton I had the same problem. And heres how I solved it: I

mounted: function() {
  document.body.appendChild(this.$el);
},

Not very smart but it does what it should.

roberttolton commented 4 years ago

Thanks @denisstasyev I'll check out Three.js - in your experience can you still do multiple marker / barcode tracking?

@nico-martin Interesting.. but not sure how appending the current component to the body would solve the <a-frame> code not being a part of that component / still only working as a root node of body? Surely they'd just end up as siblings.

denisstasyev commented 4 years ago

@nicolocarpignoli As promised, I made a separate repository with the results of my work and tips for embedding AR.js in React. You can find it here. Hope it will help a lot of people.

It contains an implementation of AR.js as a React Component for any projects. You can see this component here.

@roberttolton Unfortunately, I had no experience with multiple marker tracking. But I think that it is possible to implement this with my experience (it should not be a big problem in my implementation).

Darrel-Collinsworth commented 4 years ago

Has anyone tried using AR.JS in a svelte application? I'm currently buildling an augmented reality card game and using svelte to handle the dynamics. I'm getting an odd error where it's skewing my objects, running slow, and skewing the position so that 0 0 0 doesn't appear directly on the marker; instead it appears far to the bottom left off the marker.

Unfortunately, when I run my project through the svelte compile process, I end up with an ar.js project that performs slowly and is skewed. Both the actual shapes and the position seem to be skewed. Here is the link to the project so you can test it yourself. https://etcetera-umbrella.com/experiments/ar/ Attached is a marker that can be used to test this project and see what I'm experiencing.

I ended up making a very scaled down version of the test here : https://www.etcetera-umbrella.com/experiments/arjs/ This scaled down version of the project is just based on regular HTML and does not contain any compiling or any kind of framework. You can use the same disrupt1.png marker to see the desired effect.

I'm grateful for the community and the awesome work being done to AR.JS!

-Darrel

disrupt1

JustinStoddard commented 4 years ago

@denisstasyev You are the man!

denisstasyev commented 4 years ago

@JustinStoddard It's an honor for me to hear it, thank you 😊

nicolocarpignoli commented 4 years ago

@denisstasyev I missed that.. It's great work, thank you!

nicolocarpignoli commented 4 years ago

moved to new repository: https://github.com/AR-js-org/AR.js

Harriet-Blundell commented 4 years ago

I'm having issues with integrating AFrame with Vue.js. It is opening up the camera but not recognising the hiro marker. Any suggestions?

chhamza commented 4 years ago

I'm having issues with integrating AFrame with Vue.js. It is opening up the camera but not recognising the hiro marker. Any suggestions?

Can you share your repo?

rogueyoshi commented 3 years ago

@Darrel-Collinsworth did you ever have any luck getting it to run? from my experiments, what i think is happening is layout pushing the the canvases. im about to try with the barest possible setup.