diff --git a/src/HTMLMesh.js b/src/HTMLMesh.js index 4baffc3..3a3d709 100644 --- a/src/HTMLMesh.js +++ b/src/HTMLMesh.js @@ -29,6 +29,7 @@ class HTMLMesh extends Mesh { } + this.addEventListener( 'mouseleave', onEvent ); this.addEventListener( 'mousedown', onEvent ); this.addEventListener( 'mousemove', onEvent ); this.addEventListener( 'mouseup', onEvent ); @@ -43,6 +44,7 @@ class HTMLMesh extends Mesh { canvases.delete( dom ); + this.removeEventListener( 'mouseleave', onEvent ); this.removeEventListener( 'mousedown', onEvent ); this.removeEventListener( 'mousemove', onEvent ); this.removeEventListener( 'mouseup', onEvent ); @@ -73,7 +75,7 @@ class HTMLTexture extends CanvasTexture { if ( ! this.scheduleUpdate ) { // ideally should use xr.requestAnimationFrame, here setTimeout to avoid passing the renderer - this.scheduleUpdate = setTimeout( () => this.update(), 16 ); + this.scheduleUpdate = setTimeout( () => this.update(), 100 ); } @@ -121,6 +123,18 @@ class HTMLTexture extends CanvasTexture { } +// Those are all css properties we use in this file: +const USED_CSS_PROPERTIES = [ + 'backgroundColor', 'color', + 'borderRadius', + 'borderTopWidth', 'borderTopColor', 'borderTopStyle', + 'borderLeftWidth', 'borderLeftColor', 'borderLeftStyle', + 'borderBottomWidth', 'borderBottomColor', 'borderBottomStyle', + 'borderRightWidth', 'borderRightColor', 'borderRightStyle', + 'accentColor', 'fontFamily', 'fontWeight', 'fontSize', 'textTransform', + 'paddingLeft', 'paddingTop', 'paddingBottom', 'paddingRight', + 'overflow' +]; // @@ -243,6 +257,38 @@ function html2canvas( element ) { } + function getStyleForElement( element ) { + const style = window.getComputedStyle( element ); + if ( element instanceof HTMLButtonElement ) { + if ( element.dataset.hoverStyleStored !== 'true' ) { + // The first time we render, store hover style in data attributes to make + // hover style work in VR because style aren't recomputed when we add the + // hover class. + if ( element.dataset.hoverStyleStored !== 'pending' ) { + // The mutation observer won't trigger rerender if we add the class now because we're currently rendering (scheduleUpdate is defined) + // Wait end of render before we modify the DOM. + element.dataset.hoverStyleStored = 'pending'; + queueMicrotask( () => { + // Disable any css transition to avoir having a + // background color in between states when rerender is triggered. + element.style.transitionDuration = '0s'; + element.classList.add( 'hover' ); + } ); + } else if ( element.classList.contains( 'hover' ) ){ + // rerender was called, now store the updated computed style for hover + for ( const prop of USED_CSS_PROPERTIES ) { + element.dataset[prop] = style[prop]; + } + element.dataset.hoverStyleStored = 'true'; + queueMicrotask( () => { + element.classList.remove( 'hover' ); + } ); + } + } + } + return element.classList.contains( 'hover' ) && element.dataset.hoverStyleStored === 'true' ? element.dataset : style; + } + function drawElement( element, style ) { let x = 0, y = 0, width = 0, height = 0; @@ -288,7 +334,7 @@ function html2canvas( element ) { width = rect.width; height = rect.height; - style = window.getComputedStyle( element ); + style = getStyleForElement( element ); // Get the border of the element used for fill and border @@ -526,6 +572,16 @@ function htmlevent( element, event, x, y ) { element.dispatchEvent( new MouseEvent( event, mouseEventInit ) ); + if ( element instanceof HTMLButtonElement ) { + switch ( event ) { + case 'mousemove': + if ( !element.classList.contains( 'hover' ) ) { + element.classList.add('hover'); + } + break; + } + } + if ( element instanceof HTMLInputElement && element.type === 'range' && ( event === 'mousedown' || event === 'click' ) ) { const [ min, max ] = [ 'min', 'max' ].map( property => parseFloat( element[ property ] ) ); @@ -538,6 +594,10 @@ function htmlevent( element, event, x, y ) { } + } else { + if ( element instanceof HTMLButtonElement ) { + if ( element.classList.contains( 'hover' ) ) element.classList.remove( 'hover' ); + } } for ( let i = 0; i < element.childNodes.length; i ++ ) { diff --git a/src/aframe-html.js b/src/aframe-html.js index ac4cf3d..6a39577 100644 --- a/src/aframe-html.js +++ b/src/aframe-html.js @@ -78,6 +78,10 @@ AFRAME.registerComponent('html', { } if (type === 'mouseleave' && this.activeRaycaster === raycaster) { this.activeRaycaster = null; + _event.type = type; + _event.data.set( -1, -1 ); + const mesh = this.el.getObject3D('html'); + mesh.dispatchEvent( _event ); } if (this.cursor) this.cursor.visible = false; if (intersection) {