AR-js-org / AR.js

Image tracking, Location Based AR, Marker tracking. All on the Web.
MIT License
5.3k stars 909 forks source link

Attribute values missing on entities added on the fly #557

Closed Platform-Group closed 10 months ago

Platform-Group commented 11 months ago

Do you want to request a feature or report a bug?

Bug

What is the current behavior?

Html is added but with missing attributes

If the current behavior is a bug, please provide the steps to reproduce.

      let locations = [
        {
          latitude: "51.505867",
          longitude: "-0.075123",
          scale: [300, 300, 300],
          name: "Tower Bridge"
        },
        {
          latitude: "51.527631",
          longitude: "-0.152144",
          scale: [300, 300, 300],
          name: "Queen Mary's Garden"
        },
        {
          latitude: "51.556692",
          longitude: "-0.279666",
          scale: [300, 300, 300],
          name: "Wembley Stadium"
        }
      ]
      for (let i = 0; i < locations.length; i++) {
        let location = locations[i]
        const entity = document.createElement("a-entity");
        entity.setAttribute('gps-new-entity-place', `latitude: ${location.latitude}; longitude: ${location.longitude};`)
        entity.setAttribute("scale", location.scale);
        entity.setAttribute("look-at", "[gps-new-camera]")
        const pin = document.createElement('a-entity')
        pin.setAttribute('gltf-model', '/assets/map_pin/scene.gltf')
        entity.appendChild(pin)
        const text = document.createElement("a-text");
        text.setAttribute("scale", {
          x: 0.7,
          y: 0.7,
          z: 0.7,
        });
        text.setAttribute("position", {
          x: 0,
          y: 0.6,
          z: 0,
        });
        text.setAttribute("value", location.name);
        text.setAttribute("align", "center");
        entity.appendChild(text);
        document.querySelector('#location-grouping').appendChild(entity)
      }

Results in:

<a-entity gps-new-entity-place="" scale="" look-at=""><a-entity gltf-model=""></a-entity><a-text scale="" position="" value="Tower Bridge" align="center" text=""></a-text></a-entity>
<a-entity gps-new-entity-place="" scale="" look-at=""><a-entity gltf-model=""></a-entity><a-text scale="" position="" value="Queen Mary's Garden" align="center" text=""></a-text></a-entity>
<a-entity gps-new-entity-place="" scale="" look-at=""><a-entity gltf-model=""></a-entity><a-text scale="" position="" value="Wembley Stadium" align="center" text=""></a-text></a-entity>

As you can see, most of the attributes have missing values. I've attempted timeouts, doing this from AFRAME component inits or schemaUpdates, from window.onLoad.

What's weird though is I know that in some cases you can add new entities on the fly, for example:

 let testEntityAdded = false;
    const entity = document.createElement("a-triangle");
    entity.setAttribute("scale", {
      x: 20,
      y: 20,
      z: 20,
    });
    entity.setAttribute("material", { color: "red" });
    const text = document.createElement("a-text");
    text.setAttribute("scale", {
      x: 4,
      y: 4,
      z: 4,
    });
    text.setAttribute("position", {
      x: 0,
      y: 1,
      z: 0,
    });
    text.setAttribute("value", "N");
    text.setAttribute("align", "center");
    entity.appendChild(text);
    document
      .querySelector("#camera")
      .addEventListener("gps-camera-update-position", (e) => {
        console.log("gps position updated", e.detail.position);
        entity.setAttribute("gps-new-entity-place", {
          latitude: e.detail.position.latitude + 0.001,
          longitude: e.detail.position.longitude,
        });
        if (!testEntityAdded) {
          // Add a triangle to the north of the initial GPS position
          document.querySelector("a-scene").appendChild(entity);
        }
        testEntityAdded = true;
      });

Which seems to work fine, however I can't for the life of me figure out what the difference is. Aframe docs seem to indicate that there shouldn't be any issues with adding entities with javascript on the fly, so I'm not sure what's going wrong here. I can only assume it's an issue with how ar.js initalises.

What is the expected behavior?

Entities are created without missing attributes

Also it seems like this has been an issue for over three years: https://stackoverflow.com/questions/62903240/setattribute-does-not-set-value

nickw1 commented 11 months ago

I'm not sure to be honest, but does the data of the gps-new-entity-place initialise properly?

In any case you can always initialise using the method shown in the second example, by passing in objects containing the attributes you want to set.

herrpedro commented 11 months ago

sorry for the naiv suggestion aren't you missing a ; after let location = locations[i] did you check console and add some console.log in your code to check if you have the right values/variables/scopes?

Platform-Group commented 11 months ago

@nickw1

Doesn't seem to make a difference if I change the setAttribute of gps-new-entity-place to an object:

      entity.setAttribute('gps-new-entity-place', { 
        latitude: location.latitude, 
        longitude: location.longitude
      })
<a-entity gps-new-entity-place="" scale="" look-at=""><a-entity gltf-model=""></a-entity><a-text scale="" position="" value="Tower Bridge" align="center" text=""></a-text></a-entity>

It does seem like gps-new-entity-place init() and update() are both getting latitude and longitude correctly somehow though. I added console logs and they come out fine:

gps-new-entity-place.js:17 init new {latitude: 51.556692, longitude: -0.279666} gps-new-entity-place.js:36 update new {latitude: 51.556692, longitude: -0.279666} x3

Odd that the attributes shown on the elements aren't correct and that they don't appear then.

Platform-Group commented 11 months ago

@herrpedro you don't need semicolons in js, you can see most are missing in my code, I normally don't bother with them but I'm currently copying bits in and out all over and I'm not bothering to lint too much and some are left in from copied example code.

And yes I checked the variables are all correct at various points, I also checked to see if it makes a difference as to whether or not I use strings vs floats for lat and long but it seems to be broken either way.

I do invite you and @nickw1 to give the code a try yourself, or if you have example code of something like this I'd love to see if I can figure out where I'm going wrong. I'm guessing there's a particular broken component or something that's caused the example to work and my code to not work.

herrpedro commented 11 months ago

@Platform-Group i'm still in the part of writing code that works in all browsers. So far only firefox in android works ok. all the others need "simulated" coordinates to show the boxes in the right coordinates so i opened a bug of my own.. may be you can read it too and say something.. the thing is that it's so simple code that I dont know why it does not work, its #558

already interacting with clicks and js and already building an api so all comes from server-side according to some things

meanwhile i keep reading docs and examples and imagining uses

herrpedro commented 11 months ago

@Platform-Group

happens inside of this the attributes disappear when adding this js (same with the -nft)

this is to the extent of my poor knowledge now i'll look into mine :)

all the best

nickw1 commented 10 months ago

@nickw1

Doesn't seem to make a difference if I change the setAttribute of gps-new-entity-place to an object:

      entity.setAttribute('gps-new-entity-place', { 
        latitude: location.latitude, 
        longitude: location.longitude
      })
<a-entity gps-new-entity-place="" scale="" look-at=""><a-entity gltf-model=""></a-entity><a-text scale="" position="" value="Tower Bridge" align="center" text=""></a-text></a-entity>

It does seem like gps-new-entity-place init() and update() are both getting latitude and longitude correctly somehow though. I added console logs and they come out fine:

gps-new-entity-place.js:17 init new {latitude: 51.556692, longitude: -0.279666} gps-new-entity-place.js:36 update new {latitude: 51.556692, longitude: -0.279666} x3

Odd that the attributes shown on the elements aren't correct and that they don't appear then.

Strange, I've used this method of setting attributes many times and it works, see the examples in the new-location-based directory within aframe in the repo, for example. Let me try your example. So the POIs don't appear at the expected place?

nickw1 commented 10 months ago

@herrpedro you don't need semicolons in js, you can see most are missing in my code, I normally don't bother with them but I'm currently copying bits in and out all over and I'm not bothering to lint too much and some are left in from copied example code.

And yes I checked the variables are all correct at various points, I also checked to see if it makes a difference as to whether or not I use strings vs floats for lat and long but it seems to be broken either way.

I do invite you and @nickw1 to give the code a try yourself, or if you have example code of something like this I'd love to see if I can figure out where I'm going wrong. I'm guessing there's a particular broken component or something that's caused the example to work and my code to not work.

See for example:

https://github.com/AR-js-org/AR.js/blob/master/aframe/examples/new-location-based/poi/index.js

This is very similar in concept, it's adding the POIs using JSON returned from a web API, by dynamically setting gps-new-entity-place.

nickw1 commented 10 months ago

@Platform-Group I have got your code working, one issue was that the scale needs to be a JS object with attributes for x, y and z. I had to make some changes as I don't have your pin asset, but this example works:

<!DOCTYPE html>
<html>
<head>
<title>AR.js A-Frame - Points of Interest Example</title>
<script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script>
<script type='text/javascript' src='../../../../three.js/build/ar-threex-location-only.js'></script> 
<script type='text/javascript' src='../../../build/aframe-ar.js'></script>
<script type='text/javascript' src='index.js'></script>
</head>
<body>
<a-scene vr-mode-ui='enabled: false' arjs='sourceType: webcam; videoTexture: true; debugUIEnabled: false' renderer='antialias: true; alpha: true'>
    <a-camera gps-new-camera='gpsMinDistance: 5; simulateLatitude: 51.505; simulateLongitude: -0.0751'></a-camera>
</a-scene>

</body>
</html>

JS:

window.onload = () => {

    const scene = document.querySelector("a-scene");

    let locations = [
        {
          latitude: "51.505867",
          longitude: "-0.075123",
          scale: { x: 20, y: 20, z: 20},
          color: 'yellow',
          name: "Tower Bridge"
        },
        {
          latitude: "51.527631",
          longitude: "-0.152144",
          scale: { x: 20, y: 20, z: 20},
          color: 'blue',
          name: "Queen Marys Garden"
        },
        {
          latitude: "51.556692",
          longitude: "-0.279666",
          scale: { x: 20, y: 20, z: 20},
          color: 'green',
          name: "Wembley Stadium"
        }
      ];

    for (let i = 0; i < locations.length; i++) {
        let loc = locations[i]
        const entity = document.createElement('a-entity');
        entity.setAttribute('gps-new-entity-place',
            `latitude: ${loc.latitude}; longitude: ${loc.longitude}`
        );
        entity.setAttribute("look-at", "[gps-new-camera]")
        entity.setAttribute("scale", loc.scale);
        const pin = document.createElement('a-box')
//        pin.setAttribute("scale", { x: 100000, y: 100000, z: 100000 } ); 
//        pin.setAttribute('gltf-model', '/assets/map_pin/scene.gltf')

        entity.appendChild(pin)
        pin.setAttribute("material", { color: loc.color });
        const text = document.createElement("a-text");
        text.setAttribute("scale", {
          x: 0.7,
          y: 0.7,
          z: 0.7,
        });
        text.setAttribute("position", {
          x: 0,
          y: 0.6,
          z: 0,
        });
        text.setAttribute("value", loc.name);
        text.setAttribute("align", "center");
        entity.appendChild(text);
 //       document.querySelector('#location-grouping').appendChild(entity)
        scene.appendChild(entity);
    }
};

This is assuming a local installation of AR.js, you will need to obviously change the AR.js location.

herrpedro commented 10 months ago

yep. it works but once simulateLatitute and simulateLongitude are removed and latlon coordinates of "locations" are adjusted to your location.... stops working (only works in ffox)

nickw1 commented 10 months ago

yep. it works but once simulateLatitute and simulateLongitude are removed and latlon coordinates of "locations" are adjusted to your location.... stops working (only works in ffox)

Do you have code for this? Are the POIs definitely close enough to your real GPS position?

A good test is this example here:

https://github.com/AR-js-org/AR.js/tree/master/aframe/examples/new-location-based/

This adds entities close to your GPS position automatically, wherever you are.

Does this example work for you?

nickw1 commented 10 months ago

@herrpedro sorry, wrong path for the example:

Should be: (EDITED)

https://github.com/AR-js-org/AR.js/tree/master/aframe/examples/new-location-based/basic-js

It's available in the repo and can be tested by starting a server in the root directory of the repo and navigating to the example.

Platform-Group commented 10 months ago

Thanks @nickw1 that works great, do you know any way to turn on some kind of debugging though so I get error messages in my console for things like the wrong input type? Seems mad that it just silently fails so often, I could be making mistakes constantly and not know about it.

nickw1 commented 10 months ago

@Platform-Group great! Not sure but this may be of interest:

https://aframe.io/docs/1.4.0/introduction/visual-inspector-and-dev-tools.html