jonobr1 / two.js

A renderer agnostic two-dimensional drawing api for the web.
https://two.js.org
MIT License
8.31k stars 455 forks source link

[Question] Using a renderer directly with a shape from a custom build #564

Closed NoneOfMaster closed 3 years ago

NoneOfMaster commented 3 years ago

I think I'm missing a step, or the documentation, or both for how to use just a shape and a renderer together outside the Two class.

My aim is to reduce the amount of code necessary for using a subset of shapes by customizing the utils/build.js file to only export what I need as suggest in the Custom Build section of the README. In this example, that is the svg renderer and the ellipse:

// utils/build.js

async function build() {
  // ...

  await buildModule("src/renderers/svg.js", "Two", "build/");
  await buildModule("src/shapes/ellipse.js", "Two", "build/");

  // ...
}

However, I don't appear to be using these together correctly. I'm using a React app but I am able to reproduce this minimally using just the exports for illustration purposes:

<!-- index.html -->

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
  </head>

  <body>
    <script src="dist/bundle.js"></script>
    <div
      id="test"
      style="width: 500px; height: 500px; background-color: blue"
    ></div>
  </body>
</html>
// index.js

import Ellipse from "two.js/src/shapes/ellipse";
import SvgRenderer from "two.js/src/renderers/svg";

document.addEventListener("DOMContentLoaded", function (event) {
  const domElement = document.getElementById("test");
  const renderer = new SvgRenderer({ domElement });
  renderer.setSize(200, 200);
  const shape = new Ellipse(0, 0, 100, 100);
  renderer.scene.add(shape);
  renderer.render();
});

I bundled the above with webpack and the result of opening index.html in the browser is the same I see with my React app. All the code runs, but I don't see the shape. The svg element seems to have no dimensions. No doubt I'm missing a step or the documentation that explains how to do this. This is an approximation I've gathered just by looking over src/Two.js.

What I'm hoping for is the equivalent behavior of what it would be with the Two class, such as the below which does work:

import Two from "two.js/src/Two";

document.addEventListener("DOMContentLoaded", function (event) {
  const domElement = document.getElementById("test");
  const two = new Two({ width: 200, height: 200 }).appendTo(domElement);
  const shape = two.makeEllipse(0, 0, 100, 100);
  two.update();
});

Environment (please select one):


jonobr1 commented 3 years ago

Thanks for posting your question. I'm sorry, but I don't I totally understand what you're asking help on. Are you having trouble making it work using React App and importing like import SvgRenderer from 'two.js/src/renderers/svg.js' or with the using the Custom Build code?

If you're using React App, then you shouldn't have to rely on the Custom Build code.

NoneOfMaster commented 3 years ago

Thanks for posting your question. I'm sorry, but I don't I totally understand what you're asking help on. Are you having trouble making it work using React App and importing like import SvgRenderer from 'two.js/src/renderers/svg.js' or with the using the Custom Build code?

The imports themselves seem to be importing correctly regardless of framework. My question is why the following are not equivalent:

  // when importing all of Two    
  const domElement = document.getElementById("test");
  const two = new Two({ width: 200, height: 200 }).appendTo(domElement);
  const shape = two.makeEllipse(0, 0, 100, 100);
  two.update();
  // when importing SvgRenderer and Ellipse
  const domElement = document.getElementById("test");
  const renderer = new SvgRenderer({ domElement });
  renderer.setSize(200, 200);
  const shape = new Ellipse(0, 0, 100, 100);
  renderer.scene.add(shape);
  renderer.render();

The latter is how I'm attempting to implement Custom Build code (could be wrong!) and does not render an Ellipse with its inner svg.

jonobr1 commented 3 years ago

Ahhh, got it. That's because SvgRenderer expects an <svg /> to be its domElement. So you can supply a <div /> and you need to append it. In your example it would be like this:

const domElement = document.querySelector('#test');
const renderer = new SvgRenderer();
domElement.appendChild(renderer.domElement);
// The rest of your code

Hope that helps!

NoneOfMaster commented 3 years ago

Totally! I just had to add an empty params object to the renderer instantiation and then that did it. Thanks you!