0

Goal is to show multiple .stl-files in different divs on a webpage and get the model information per model (volume, area, xyz, etc.). Therefore I use https://www.viewstl.com/plugin/#params, which is based on three.js

I code the index.html:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  </head>
  <body>
    <main id="main"></main>

    <script src="stl_viewer.min.js"></script>
    <script src="tq_ini_stlviewer.js"></script>
  </body>
</html>

The javascript code:

// Loop for 3 stl-files
for (var modelNo = 0; modelNo < 3; modelNo++) {
  var orderPosition = document.createElement("div"); // Create div element
  var createClass = "drag-area" + modelNo; // Create class
  orderPosition.classList.add(createClass); // Add class to element

  var main = document.getElementById("main"); // Add element to DOM
  main.appendChild(orderPosition);

  var stlDatei = "./models/" + modelNo + ".stl"; // Create path
  console.log("Model-No.: " + modelNo);
  console.log("STL-File: " + stlDatei);
  /* Create StlViewer object for each class and dedicate id and stl-file to it.
  Wait for callback that file is loaded, then call function 'dimensions'*/
  var stl_viewer = new StlViewer(document.querySelector("." + createClass), { 
    models: [{ id: modelNo, filename: stlDatei }],
    model_loaded_callback: dimensions,
  }); 
}

function dimensions(modelNo) {
  console.log("Dimensions for model: " + modelNo);
  var model_info = window.stl_viewer.get_model_info(modelNo);
  var Volume = (model_info.volume / 1000).toLocaleString(undefined, {
    minimumFractionDigits: 2,
    maximumFractionDigits: 2,
  });
  var BoundBox = (
    (model_info.dims.x * model_info.dims.y * model_info.dims.z) /
    1000
  ).toLocaleString(undefined, {
    minimumFractionDigits: 2,
    maximumFractionDigits: 2,
  });
  var Area = (model_info.area / 1000).toLocaleString(undefined, {
    minimumFractionDigits: 2,
    maximumFractionDigits: 2,
  });
  console.log(
    "Model-ID: " +
      modelNo +
      "\n" +
      "Name: " +
      model_info.name +
      "\n" +
      "Volumen: " +
      Volume +
      " cm³\n" +
      "Bounding Box Volumen: " +
      BoundBox +
      " cm³\n" +
      "Oberfläche: " +
      Area +
      " cm²\n" +
      "Länge: " +
      model_info.dims.x.toLocaleString(undefined, {
        minimumFractionDigits: 2,
        maximumFractionDigits: 2,
      }) +
      " mm\n" +
      "Breite: " +
      model_info.dims.y.toLocaleString(undefined, {
        minimumFractionDigits: 2,
        maximumFractionDigits: 2,
      }) +
      " mm\n" +
      "Höhe: " +
      model_info.dims.z.toLocaleString(undefined, {
        minimumFractionDigits: 2,
        maximumFractionDigits: 2,
      }) +
      " mm\n" +
      "Dreiecksfacetten: " +
      model_info.triangles.toLocaleString(undefined, {
        minimumFractionDigits: 0,
        maximumFractionDigits: 0,
      })
  );
}

Expected output in console

model information for stl-file 0, 1 and 2 like

  • Model-ID: 0
  • Name: ./models/0.stl
  • Volumen: 23,76 cm³
  • Bounding Box Volumen: 145,01 cm³
  • etc.

Instead I get

  • model information for stl-file 2 only and
  • two error-messages for stl-file 0 and 1:

get_model_info - id not found: 0 "Uncaught TypeError: Cannot read properties of undefined (reading 'x') at StlViewer.dimensions [as model_loaded_callback]

get_model_info - id not found: 1 "Uncaught TypeError: Cannot read properties of undefined (reading 'x') at StlViewer.dimensions [as model_loaded_callback]

@trincot: this is the output of console.log(JSON.sstringify(model_info, null, 2)):

{
  "name": "./models/2.stl",
  "orig_filename": null,
  "position": {
    "x": 0,
    "y": 0,
    "z": 0
  },
  "dims": {
    "x": 102.5,
    "y": 86,
    "z": 16.450000762939453
  },
  "rotation": {
    "x": 0,
    "y": 0,
    "z": 0
  },
  "display": "flat",
  "color": null,
  "scale": {
    "x": 1,
    "y": 1,
    "z": 1
  },
  "volume": 23762.741633293106,
  "area": 18429.489759870332,
  "triangles": 6012,
  "units": "mm",
  "opacity": 1
}

It seems, that the model_loaded_callback is an asynchrone process and the for-loop is not waiting.

How can I resolve the problem to get model information of all models?

Best regards Martin

  • Does this answer your question? [Wait for async task to finish](https://stackoverflow.com/questions/18729761/wait-for-async-task-to-finish) – Justinas Apr 08 '22 at 08:51
  • *"I only get the model information from the last model no. 2"*: what exactly did you look at to determine you only "get" the last model? What do you expect as output that is different from what you get now? True, this is asynchronous, but you do act on every asynchronous event. Why do you *need* the for loop to wait? Is there any dependency that the second iteration needs to rely on? – trincot Apr 08 '22 at 09:17
  • @Justinas: I tried to re-code with this example, but got the same result. – Martin Silberkuhl Apr 08 '22 at 09:24
  • It should be simple. Just write "Expected output: ... The output I get instead: ...". Don't include more than necessary in the output for us to understand the difference. Type the text (copy/paste) -- don't include images of what is essentially text. – trincot Apr 08 '22 at 09:32
  • @trincot: it's a pity, that I can't upload an image of my webpage incl. the console ... Let's try to explain ... I get the following messages: "Model-No.: 0" | "STL-File: ./models/0.stl" | "Model-No.: 1" | "STL-File: ./models/1.stl" | "Model-No.: 2" | "STL-File: ./models/2.stl" | "Dimensions for model: 0" with error "Uncaught TypeError: Cannot read properties of undefined (reading 'x'), same for model 1. For model 2 the console shows me all model information as aspected. – Martin Silberkuhl Apr 08 '22 at 09:36
  • Can you edit your question? This is not very readable in the comment section. Make sure it is clear what is the difference between: (1) what you currently get as output (2) what you desire to get as output. – trincot Apr 08 '22 at 09:37
  • If you get an **error** message, and *that* is your problem, then please make this very clear in your question. – trincot Apr 08 '22 at 09:38
  • Please clarify your specific problem or provide additional details to highlight exactly what you need. As it's currently written, it's hard to tell exactly what you're asking. – Community Apr 08 '22 at 10:03

1 Answers1

1

The problem is that you access stl_viewer in the dimensions callback, which by the time that function runs has already been overwritten by the last instance of StlViewer. The references to the two previous instances have been lost.

There are several ways to avoid this loss of references. One is to store them in an array, using the model number as index.

Assuming that the dimensions function gets the same modelNo value as argument as you have used in the loop, it should work like this:

var stl_viewer = []; // array to have access to ALL instances
for (var modelNo = 0; modelNo < 3; modelNo++) {
  // ...etc...
  // ADD to that array
  stl_viewer.push(new StlViewer(document.querySelector("." + createClass), { 
    models: [{ id: modelNo, filename: stlDatei }],
    model_loaded_callback: dimensions,
  })); 
}

function dimensions(modelNo) {
  console.log("Dimensions for model: " + modelNo);
  // Access the appropriate StlViewer instance:
  var model_info = window.stl_viewer[modelNo].get_model_info(modelNo);
  // ...etc...
}
trincot
  • 317,000
  • 35
  • 244
  • 286