Skip to content
Advertisement

Why is position set to absolute even though I have explicitly set position to unset?

Making a 3D news web app using javascript – https://shange-fagan.github.io/globe.news/

enter image description here

I am getting the message in the console that the position of my html element is set to absolute even though in the code I have explicitly set it to unset, here is my code:

    <head>
      <rssapp-ticker id="tRj0yIAl7HEk9RzX"></rssapp-ticker>
      <script
        src="https://widget.rss.app/v1/ticker.js"
        type="text/javascript"


 async
  ></script>
  <rssapp-wall id="tszZCksFzEB4w9UN"></rssapp-wall>

  <style>
    body {
      margin: 0;
    }
  </style>

  <script src="//unpkg.com/three"></script>

  <script src="//unpkg.com/globe.gl"></script>
  <!--  <script src="../../dist/globe.gl.js"></script>-->
</head>

<body>
  <div id="globeViz"></div>

  <script type="module">
    var my_awesome_script;

    // Gen random data
    const N = 30;
    const gData = [...Array(N).keys()].map(() => ({
      lat: (Math.random() - 0.5) * 180,
      lng: (Math.random() - 0.5) * 360,
    }));

    import { GUI } from "./js/dat.gui.module.js";
    // GUI

    const gui = new GUI();

    const textureLoader = new THREE.TextureLoader();
    const myTexture = [
      textureLoader.load("//unpkg.com/three-globe/example/img/earth-dark.jpg"),
      textureLoader.load(
        "//unpkg.com/three-globe/example/img/earth-blue-marble.jpg"
      ),
    ];

    const parameters = {
      Theme: 0,
    };

    const updateAllMaterials = () => {
      scene.traverse((child) => {
        if (
          child instanceof Globe() &&
          child.material instanceof THREE.MeshPhongMaterial
        ) {
          child.material = myTexture[parameters.Theme];
          child.material.needsUpdate = true;
        }
      });
    };

    gui
      .add(parameters, "Theme", {
        night: 0,
        day: 1,
      })
      .onFinishChange(() => {
        updateAllMaterials();
      });

    gui.open();

    const elem = document.getElementById("globeViz");
    const globe = Globe()
      .globeImageUrl(
        "//unpkg.com/three-globe/example/img/earth-blue-marble.jpg"
      )(elem)
      //.globeMaterial([MeshPhongMaterial])
      .bumpImageUrl("//unpkg.com/three-globe/example/img/earth-topology.png")
      .backgroundImageUrl("//unpkg.com/three-globe/example/img/night-sky.png")
      .showGraticules(true)
      .showAtmosphere(true)
      .htmlElementsData(gData)
      .htmlElement(({}) => {
        var my_awesome_script = document.createElement("iframe");
        my_awesome_script.type = "iframe";
        my_awesome_script.async = true;
        my_awesome_script.setAttribute(
          "src",
          "https://rss.app/embed/v1/wall/t0OXjFMGzjEUhPqm"
        );
        //my_awesome_script.setAttribute("class", "card");
        return `
     <link rel="stylesheet" href="input.css"> <!--Copy this line of code-->
    <div>${my_awesome_script}</div>
        `;
        my_awesome_script.style.background = "none";
        my_awesome_script.style.border = "none";
    //position is clearly set to unset
        my_awesome_script.style.position = "unset";
        my_awesome_script.style.objectFit = "contain";
        my_awesome_script.style.width = 20;
        my_awesome_script.style.height = 30;
        document.getElementById("iframe").style.position = "unset";
        document.getElementsByClassName("card").style.position = "unset";
      });

    // custom globe material
    const globeMaterial = globe.globeMaterial();
    globeMaterial.bumpScale = 10;
    new THREE.TextureLoader().load(
      "//unpkg.com/three-globe/example/img/earth-water.png",
      (texture) => {
        globeMaterial.specularMap = texture;
        globeMaterial.specular = new THREE.Color("grey");
        globeMaterial.shininess = 15;
      }
    );

    setTimeout(() => {
      // wait for scene to be populated (asynchronously)
      const directionalLight = globe
        .scene()
        .children.find((obj3d) => obj3d.type === "DirectionalLight");
      directionalLight && directionalLight.position.set(1, 1, 1); // change light position to see the specularMap's effect
    });

    globe.controls().autoRotate = true;
    globe.controls().autoRotateSpeed = 0.85;

    //const animate = () => {
    //requestAnimationFrame(animate);
    //globe.rotation.y += 0.01;
    //}

    //animate();
  </script>
</body>

please let me know what I am doing wrong, not sure if its because the src of my html element has its own styling which I don’t have access to or if I should be using typescript instead of javascript.

edit: here is a screenshot of the element and its parent in the elements tab in the devtools, as you can see the element is contained within a script tag using var my_element = document.createElement(element) and it has to be this way because I need the html element to display on the 3d globe which is using javascript enter image description here enter image description here

2nd edit: screenshot of new errors after implementing suggested code: enter image description here

3rd edit: after fixing the rss news widget embed link it is starting to display but not in the way I want, its displaying the widget above the globe instead of on the globe as is preferred: enter image description here ideally the widget would be hovering over the globe like in these markers example enter image description here

Edit: the basic version is working now but I can’t stop the markers from displaying randomly and not above each country, here is the error I get when I try to replace the random markers with the latitudes and longitudes of each country from a json file: enter image description here here is the code for replacing random markers for markers above each country specifically:

//fetch the json file containing latitude and longitude of all countries
        fetch('./country_codes.json').then(r => r.json()).then(countryLocations => {
      globe.htmlElementsData(countryLocations);
    });

edit: screenshot of working html markers that display news widgets with country locations: enter image description here

enter image description here enter image description here

Advertisement

Answer

Your error

Your error came from globe.gl when you call Globe().htmlElement({} => html) without a valid argument. There are multiple errors in how you created script tags and define the iframe. The style position error is unrelated to your line my_awesome_script.style.position = "unset";.

Using the inspector, variable t shows that you’re returning the iframe as a string ("n...<iframe ...") instead of a valid HTML element. Hence it creates the error on line 37713 when defining style on the element.

enter image description here

Solution

The below edits to your globe object should give you the preferred results. It was based on your index6.html. See comments for detailed explanations

const globe = Globe()
      .globeImageUrl(
        "//unpkg.com/three-globe/example/img/earth-blue-marble.jpg"
      )(elem)
      //.globeMaterial([MeshPhongMaterial])
      .bumpImageUrl("//unpkg.com/three-globe/example/img/earth-topology.png")
      .backgroundImageUrl("//unpkg.com/three-globe/example/img/night-sky.png")
      .showGraticules(true)
      .showAtmosphere(true)
      .htmlElementsData(gData)
      .htmlElement((d) => {

        // for debug. based on https://globe.gl/example/html-markers/
        console.log(d)
        
        // this element should be script instead of div
        // var my_awesome_script = document.createElement("div");
        var my_awesome_script = document.createElement("script");
        my_awesome_script.type = "text/javascript";
        my_awesome_script.async = true;
        my_awesome_script.setAttribute(
          "src",
          "https://widget.rss.app/v1/wall.js"
        );
        
        // you don't need to add class to the script tag
        // my_awesome_script.setAttribute("class", "card");

        // Returning the iframe and my_awesome_script creates the error. 
        // Instead, you should handle the iframe string and my_awesome_script script element separately
        // return `<iframe width="900" height="1600" style="border:none, background:none, position: unset;" src="https://rss.app/embed/v1/wall/t0OXjFMGzjEUhPqm" frameborder="0"></iframe><link rel="stylesheet" href="input.css"> <!--Copy this line of code--><div class="card">${my_awesome_script}</div>`;

        // For clarity, let's put this iframe string in its own variable without the my_awesome_script
        let my_html_string = `<iframe width="900" height="1600" style="border:none, background:none, position: unset;" src="https://rss.app/embed/v1/wall/t0OXjFMGzjEUhPqm" frameborder="0"></iframe>
          <link rel="stylesheet" href="input.css"> <!--Copy this line of code-->
          <div class="card"></div>`;
        
        // create an empty div element
        let wrapper = document.createElement('div')

        // add your string here to turn it into an HTML element
        wrapper.innerHTML = my_html_string

        // append your script HTML element
        wrapper.appendChild(my_awesome_script)

        // return everything as HTML element containing both iframe and script
        return wrapper; 

        // anything below return has no effect, also no point applying style to a script tag 

        // my_awesome_script.style.background = "transparent";
        // my_awesome_script.style.objectFit = "contain";
        // my_awesome_script.style.position = "static";
        // document.getElementById("div").style.position = "static";
        // document.getElementsByClassName("card").style.position = "static";
      });

Further reading

Example of globe.gl with HTML DOM element https://globe.gl/example/html-markers/

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement