1import { 2 Matrix4, 3 Object3D, 4 Quaternion, 5 Vector3 6} from '../../../build/three.module.js'; 7 8/** 9 * Based on http://www.emagix.net/academic/mscs-project/item/camera-sync-with-css3-and-webgl-threejs 10 */ 11 12const _position = new Vector3(); 13const _quaternion = new Quaternion(); 14const _scale = new Vector3(); 15 16class CSS3DObject extends Object3D { 17 18 constructor( element ) { 19 20 super(); 21 22 this.element = element || document.createElement( 'div' ); 23 this.element.style.position = 'absolute'; 24 this.element.style.pointerEvents = 'auto'; 25 this.element.style.userSelect = 'none'; 26 27 this.element.setAttribute( 'draggable', false ); 28 29 this.addEventListener( 'removed', function () { 30 31 this.traverse( function ( object ) { 32 33 if ( object.element instanceof Element && object.element.parentNode !== null ) { 34 35 object.element.parentNode.removeChild( object.element ); 36 37 } 38 39 } ); 40 41 } ); 42 43 } 44 45 copy( source, recursive ) { 46 47 super.copy( source, recursive ); 48 49 this.element = source.element.cloneNode( true ); 50 51 return this; 52 53 } 54 55} 56 57CSS3DObject.prototype.isCSS3DObject = true; 58 59class CSS3DSprite extends CSS3DObject { 60 61 constructor( element ) { 62 63 super( element ); 64 65 this.rotation2D = 0; 66 67 } 68 69 copy( source, recursive ) { 70 71 super.copy( source, recursive ); 72 73 this.rotation2D = source.rotation2D; 74 75 return this; 76 77 } 78 79} 80 81CSS3DSprite.prototype.isCSS3DSprite = true; 82 83// 84 85const _matrix = new Matrix4(); 86const _matrix2 = new Matrix4(); 87 88class CSS3DRenderer { 89 90 constructor() { 91 92 const _this = this; 93 94 let _width, _height; 95 let _widthHalf, _heightHalf; 96 97 const cache = { 98 camera: { fov: 0, style: '' }, 99 objects: new WeakMap() 100 }; 101 102 const domElement = document.createElement( 'div' ); 103 domElement.style.overflow = 'hidden'; 104 105 this.domElement = domElement; 106 107 const cameraElement = document.createElement( 'div' ); 108 109 cameraElement.style.transformStyle = 'preserve-3d'; 110 cameraElement.style.pointerEvents = 'none'; 111 112 domElement.appendChild( cameraElement ); 113 114 this.getSize = function () { 115 116 return { 117 width: _width, 118 height: _height 119 }; 120 121 }; 122 123 this.render = function ( scene, camera ) { 124 125 const fov = camera.projectionMatrix.elements[ 5 ] * _heightHalf; 126 127 if ( cache.camera.fov !== fov ) { 128 129 domElement.style.perspective = camera.isPerspectiveCamera ? fov + 'px' : ''; 130 cache.camera.fov = fov; 131 132 } 133 134 if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); 135 if ( camera.parent === null ) camera.updateMatrixWorld(); 136 137 let tx, ty; 138 139 if ( camera.isOrthographicCamera ) { 140 141 tx = - ( camera.right + camera.left ) / 2; 142 ty = ( camera.top + camera.bottom ) / 2; 143 144 } 145 146 const cameraCSSMatrix = camera.isOrthographicCamera ? 147 'scale(' + fov + ')' + 'translate(' + epsilon( tx ) + 'px,' + epsilon( ty ) + 'px)' + getCameraCSSMatrix( camera.matrixWorldInverse ) : 148 'translateZ(' + fov + 'px)' + getCameraCSSMatrix( camera.matrixWorldInverse ); 149 150 const style = cameraCSSMatrix + 151 'translate(' + _widthHalf + 'px,' + _heightHalf + 'px)'; 152 153 if ( cache.camera.style !== style ) { 154 155 cameraElement.style.transform = style; 156 157 cache.camera.style = style; 158 159 } 160 161 renderObject( scene, scene, camera, cameraCSSMatrix ); 162 163 }; 164 165 this.setSize = function ( width, height ) { 166 167 _width = width; 168 _height = height; 169 _widthHalf = _width / 2; 170 _heightHalf = _height / 2; 171 172 domElement.style.width = width + 'px'; 173 domElement.style.height = height + 'px'; 174 175 cameraElement.style.width = width + 'px'; 176 cameraElement.style.height = height + 'px'; 177 178 }; 179 180 function epsilon( value ) { 181 182 return Math.abs( value ) < 1e-10 ? 0 : value; 183 184 } 185 186 function getCameraCSSMatrix( matrix ) { 187 188 const elements = matrix.elements; 189 190 return 'matrix3d(' + 191 epsilon( elements[ 0 ] ) + ',' + 192 epsilon( - elements[ 1 ] ) + ',' + 193 epsilon( elements[ 2 ] ) + ',' + 194 epsilon( elements[ 3 ] ) + ',' + 195 epsilon( elements[ 4 ] ) + ',' + 196 epsilon( - elements[ 5 ] ) + ',' + 197 epsilon( elements[ 6 ] ) + ',' + 198 epsilon( elements[ 7 ] ) + ',' + 199 epsilon( elements[ 8 ] ) + ',' + 200 epsilon( - elements[ 9 ] ) + ',' + 201 epsilon( elements[ 10 ] ) + ',' + 202 epsilon( elements[ 11 ] ) + ',' + 203 epsilon( elements[ 12 ] ) + ',' + 204 epsilon( - elements[ 13 ] ) + ',' + 205 epsilon( elements[ 14 ] ) + ',' + 206 epsilon( elements[ 15 ] ) + 207 ')'; 208 209 } 210 211 function getObjectCSSMatrix( matrix ) { 212 213 const elements = matrix.elements; 214 const matrix3d = 'matrix3d(' + 215 epsilon( elements[ 0 ] ) + ',' + 216 epsilon( elements[ 1 ] ) + ',' + 217 epsilon( elements[ 2 ] ) + ',' + 218 epsilon( elements[ 3 ] ) + ',' + 219 epsilon( - elements[ 4 ] ) + ',' + 220 epsilon( - elements[ 5 ] ) + ',' + 221 epsilon( - elements[ 6 ] ) + ',' + 222 epsilon( - elements[ 7 ] ) + ',' + 223 epsilon( elements[ 8 ] ) + ',' + 224 epsilon( elements[ 9 ] ) + ',' + 225 epsilon( elements[ 10 ] ) + ',' + 226 epsilon( elements[ 11 ] ) + ',' + 227 epsilon( elements[ 12 ] ) + ',' + 228 epsilon( elements[ 13 ] ) + ',' + 229 epsilon( elements[ 14 ] ) + ',' + 230 epsilon( elements[ 15 ] ) + 231 ')'; 232 233 return 'translate(-50%,-50%)' + matrix3d; 234 235 } 236 237 function renderObject( object, scene, camera, cameraCSSMatrix ) { 238 239 if ( object.isCSS3DObject ) { 240 241 object.onBeforeRender( _this, scene, camera ); 242 243 let style; 244 245 if ( object.isCSS3DSprite ) { 246 247 // http://swiftcoder.wordpress.com/2008/11/25/constructing-a-billboard-matrix/ 248 249 _matrix.copy( camera.matrixWorldInverse ); 250 _matrix.transpose(); 251 252 if ( object.rotation2D !== 0 ) _matrix.multiply( _matrix2.makeRotationZ( object.rotation2D ) ); 253 254 object.matrixWorld.decompose( _position, _quaternion, _scale ); 255 _matrix.setPosition( _position ); 256 _matrix.scale( _scale ); 257 258 _matrix.elements[ 3 ] = 0; 259 _matrix.elements[ 7 ] = 0; 260 _matrix.elements[ 11 ] = 0; 261 _matrix.elements[ 15 ] = 1; 262 263 style = getObjectCSSMatrix( _matrix ); 264 265 } else { 266 267 style = getObjectCSSMatrix( object.matrixWorld ); 268 269 } 270 271 const element = object.element; 272 const cachedObject = cache.objects.get( object ); 273
274 if ( cachedObject === undefined || cachedObject.style !== style ) { 275 276 element.style.transform = style; 277 278 const objectData = { style: style }; 279 cache.objects.set( object, objectData ); 280 281 } 282 283 element.style.display = object.visible ? '' : 'none'; 284 285 if ( element.parentNode !== cameraElement ) { 286 287 cameraElement.appendChild( element ); 288 289 } 290 291 object.onAfterRender( _this, scene, camera ); 292 293 } 294 295 for ( let i = 0, l = object.children.length; i < l; i ++ ) { 296 297 renderObject( object.children[ i ], scene, camera, cameraCSSMatrix ); 298 299 } 300 301 } 302 303 } 304 305} 306 307export { CSS3DObject, CSS3DSprite, CSS3DRenderer };
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.