Since the last post, I refined the card layout a bit. I decided that I wanted two display modes for the cards: compact and full. The compact mode is a square shape with the image and the title. The full mode has image, title, description, and any other UI controls I add later. There is a property on the card that lets me toggle the display between these two sizes. In the future I’ll look into animating the transition between these states.
Using the compact square cards makes the card group formation features easier to work with. It also allows me to show more cards in a small area then if I used the full-size cards for everything.
Having settled on a decent mockup for the card layouts, I turned my attention to card formations. I started with three simple row formations. Once the project is further along, I’ll create these formations dynamically based on the size and number of cards, and the relative position of the user. For now, I decided to hardcode a few arrays with the position of each card in each formation. I added a new helper file called
formation.js that exports the formations. I imported these into
SceneController.js and added a
v-for loop to create cards from the API data, using the index to get a position value from the active formation.
<!-- A parent entity to group the cards --> <a-entity position="0 0 -2"> <ItemCard3D v-for="(item, index) in itemResponse.data" :key="index" :item="item" :position="calculatePosition(index)" /> </a-entity>
I also setup a temporary radio box set to switch between the formations. This left me in the interesting situation of having some DOM elements bound to a property that–when changed– can cause some A-Frame entities to update their positions. This may not be the “A-Frame Way” to modify positions, but it was interesting nonetheless.
Throughout the project so far, I’ve used v-bind (or the shorthand “:”) for several A-Frame components/attributes. The ease of using v-bind with A-Frame is one of the main reasons that I added A-Frame to this series. A few examples:
:color="this.$brand.light1"– set A-Frame color with a global value defined in the brand file
:value="this.trimString(item.title.rendered, 90)"set the value of a text entity with the result of a component method
:position="calculatePosition(index)"set the position of a card with the result of a method that uses the current index to look up a position from the selected formation.
All these bindings are one way. If I update the data, the UI elements will update, but I can’t update the UI elements yet, so I have no way to update the data. While editing the API data is out of the scope of this series, I do need to setup two-way bindings for the “Favorites” feature.
As always, here is a link to the Code Sandbox for this article.
What’s next? I’m thinking about animating the transitions between the cards. I’d like a VR user to be able to select a card with a laser control. When selected, the card would move closer to the user and expand to full-size. I also want to add some UI controls in the VR scene for paging between sets of data. These features will lead me into learning more about controller interactions in A-Frame.