mflux / aframe-datguivr

A-Frame component for datGUIVR
MIT License
24 stars 7 forks source link

Binding changes to to targets. #2

Open donmccurdy opened 7 years ago

donmccurdy commented 7 years ago

Current use pattern appears to be:

<a-box position="0 0 -5" color="red" scale="1 1 1"></a-box>

<a-datgui controller-left="#ctrl-left"
          controller-right="#ctrl-right">
  <a-gui-slider name="scale"></a-gui-slider>
</a-datgui>
var el = document.querySelector('a-box');
scaleCtrl = document.querySelector('[name=scale]');
scaleCtrl.addEventListener('onChanged', function (e) {
  el.setAttribute('scale', {
    x: e.detail.value,
    y: e.detail.value,
    z: e.detail.value
  });
});

If there's a reasonably clean way of doing this, I'd love to see declarative bindings to particular components/properties. Would you (also CC @ngokevin) have any ideas or preferences about syntax?

Ideas:

<a-box id="box1"></a-box>

<a-datgui controller-left="#ctrl-left"
          controller-right="#ctrl-right"
          target-el="#box">

  <!-- Single property. -->
  <a-gui-slider name="left/right" property="position.x"></a-gui-slider>

  <!-- Multiple properties. -->
  <a-gui-slider name="resize" properties="scale.x, scale.y, scale.z"></a-gui-slider>
</a-datgui>

Thoughts? Should the target element be specified at the input level, so that the interface can affect multiple elements?

cwervo commented 7 years ago

Would it be considered bad form for a single component to have both a primitive and inline attribute syntax? Because I actually think there's actually a case for the following syntax:

<a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E"
          gui="name: MySphere; properties: scale.x, scale.y, scale.z, scale; position: -2 2 -1"></a-sphere>

(Live demo for this at this link)

I could see this being really powerful when combined with templating and mixins. IMO it's easier to reason about a GUI coming off an object's gui attribute rather than as a consequence of another component. Things like a higher level interface for multiple elements, though, make me think there are a lot of good ways to tackle this.

donmccurdy commented 7 years ago

Doesn't seem like bad form IMO, but you could arguably do the same more easily with just a primitive:

<a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E">
  <a-gui name="MySphere"
         properties="scale.x, scale.y, scale.z"
         position="0 2 0"></a-gui>
</a-sphere>

This way you can use position/rotation/scale on the GUI for free, without needing to add those to the component. By default the GUI would target the parent element (like <a-animation/> does), but perhaps there would be a target="#foo" property that would override this, letting you control different objects from a single GUI attached to your controllers.

cwervo commented 7 years ago

@donmccurdy I was really excited when I saw your comment about nesting a-gui under an object it's manipulating but then I noticed that a couple of the common properties to modify while using a gui component like this (namely rotation and scale) are problematic to inherit, scale for example:

jul-11-2017 18-24-37 live Codepen example

One way to handle this I imagine would be turning off rotation and scale inheritance by default when an a-gui is nested.

I've edited my previous Codepen to take an inheritPosition attribute (although, I suppose it would be better be called inheritInitialPos and inheritPos would be for the gui component tracking), and turned the component's position into a modifier against inheritPosition if it exists:

giphy 1

This pen's component syntax seems to be convenient for me at the moment, so I think I'll keep working on it and try and make a PR for aframe-datguivr using any of the things I learn coming out of working on it!

donmccurdy commented 7 years ago

Ok! Yeah either way seems reasonable, this looks cool.

About inheriting the parent's transforms, you can avoid that (with either syntax) by having the GUI object added to el.sceneEl.object3D, so it's always in world coordinates. Then it's just up to you to position it near the object, update when it moves, etc. Seems like that would be good sometimes, less good other times. :/