Navalex
Navalex

Reputation: 264

AFrame Text change rotation

I'm making a virtual tour using AFrame, with a <a-sky> for the 360° images, some <a-circle> for hotspots, and <a-text> below circles for indications.

My goal is to make texts always parallel to the screen. I already try the aframe-look-at-component on the camera, but it's not what I was looking for because they face a point instead of facing the screen.

So my next idea was to create an invisible cursor, and copy his rotation the the texts, but I'm not sure of this because I don't know if the cursor update his rotation or if it's only base on the cam rotation. Anyway the main source of this problem was I don't know how to change the rotation of my text after creation, I tried mytext.object3D.rotation, mytext.setAttribute('rotation', newRotation), and also object3D.lookAt(), but either it didn't matter, or it wasn't what I was looking for.

What is the best way to achieve this ?

Here my hotspot component (which create the texts based on some props):

AFRAME.registerPrimitive('a-hotspot', {
    defaultComponents: {
        hotspot: {}
    },
    mappings: {
        for: 'hotspot.for',
        to: 'hotspot.to',
        legend: 'hotspot.legend',
        'legend-pos': 'hotspot.legend-pos',
        'legend-rot': 'hotspot.legend-rot'
    }
});

AFRAME.registerComponent('hotspot', {
    schema: {
        for: { type: 'string' },
        to: { type: 'string' },
        legend: { type: 'string' },
        'legend-pos': { type: 'vec3', default: {x: 0, y: -0.5, z:0}},
        'legend-rot': { type: 'number', default: 0 },
        positioning: { type: 'boolean', default: false }
    },

    init: function () {

        this.shiftIsPress = false

        window.addEventListener('keydown', this.handleShiftDown.bind(this))
        window.addEventListener('keyup', this.handleShiftUp.bind(this))


        this.tour = document.querySelector('a-tour');
        if (this.data.legend)
            this.addText();
        this.el.addEventListener('click', this.handleClick.bind(this));
    },

    // Creating the text, based on hotspots props
    addText: function () {
        var hotspot = this.el,
            position = new THREE.Vector3(hotspot.object3D.position.x, hotspot.object3D.position.y, hotspot.object3D.position.z),
            text = document.createElement('a-text'),
            loadedScene = document.querySelector('a-tour').getAttribute('loadedScene')

        position.x += this.data['legend-pos'].x
        position.y += this.data['legend-pos'].y
        position.z += this.data['legend-pos'].z

        console.log(this.data['legend-rot'])

        // Set text attributes
        text.id = `text_${this.data.for}_to_${this.data.to}`
        text.setAttribute('position', position)
        text.setAttribute('color', '#BE0F34')
        text.setAttribute('align', 'center')
        text.setAttribute('value', this.data.legend)
        text.setAttribute('for', this.data.for)
        if (loadedScene && loadedScene !== this.data.for) text.setAttribute('visible', false)

        // Insert text after hotspot
        hotspot.parentNode.insertBefore(text, hotspot.nextSibling)
    },

    // This part is supposed to edit the rotation
    // to always fit to my idea
    tick: function () {
        if (this.el.getAttribute('visible')) {
            var cursorRotation = document.querySelector('a-cursor').object3D.getWorldRotation()

            //document.querySelector(`#text_${this.data.for}_to_${this.data.to}`).object3D.lookAt(cursorRotation)
            this.updateRotation(`#text_${this.data.for}_to_${this.data.to}`)
        }
    },

    // This parts manage the click event.
    // When shift is pressed while clicking on hotspot, it enable another component
    // to stick a hotspot to the camera for help me to place it on the scene
    // otherwise, it change the 360° image and enbable/disable hotspots.
    handleShiftDown: function (e) {
        if (e.keyCode === 16) this.shiftIsPress = true
    },

    handleShiftUp: function (e) {
        if (e.keyCode === 16) this.shiftIsPress = false
    },

    handleClick: function (e) {
        var target = 'target: #' + this.el.id
        var tour = this.tour.components['tour']

        if (this.shiftIsPress)
            tour.el.setAttribute('hotspot-helper', target)
        else
            tour.loadSceneId(this.data.to, true);
    }
});

I really don't know what to do..

EDIT: I found a part solution: If I had geometry to my text (and material with alphaTest: 1 for hide it), setAttribute('rotation') work, and I base it on camera rotation. The problem is that after that, the camera is locked, don't understand why ^^

var cursorRotation = document.querySelector('a-camera').object3D.rotation

            document.querySelector(`#text_${this.data.for}_to_${this.data.to}`).setAttribute('rotation', cursorRotation)

Thanks, Navalex

Upvotes: 1

Views: 432

Answers (2)

Kyle Baker
Kyle Baker

Reputation: 3712

Be sure to check out the example here: https://stemkoski.github.io/A-Frame-Examples/sprites.html

The 'box' sign is always visible to user

Upvotes: 2

Navalex
Navalex

Reputation: 264

I finally found the solution !

Instead of document.querySelector('a-camera').object3D.rotation, I used document.querySelector('a-camera').getAttribute('rotation') and it's work nice !

Upvotes: 2

Related Questions