diff --git a/extlib/STLExporter.js b/extlib/STLExporter.js deleted file mode 100644 index 606b17c..0000000 --- a/extlib/STLExporter.js +++ /dev/null @@ -1,209 +0,0 @@ -import { - Vector3 -} from '../../../build/three.module.js'; - -/** - * Usage: - * var exporter = new STLExporter(); - * - * // second argument is a list of options - * var data = exporter.parse( mesh, { binary: true } ); - * - */ - -var STLExporter = function () {}; - -STLExporter.prototype = { - - constructor: STLExporter, - - parse: function ( scene, options ) { - - if ( options === undefined ) options = {}; - - var binary = options.binary !== undefined ? options.binary : false; - - // - - var objects = []; - var triangles = 0; - - scene.traverse( function ( object ) { - - if ( object.isMesh ) { - - var geometry = object.geometry; - - if ( geometry.isBufferGeometry !== true ) { - - throw new Error( 'THREE.STLExporter: Geometry is not of type THREE.BufferGeometry.' ); - - } - - var index = geometry.index; - var positionAttribute = geometry.getAttribute( 'position' ); - - triangles += ( index !== null ) ? ( index.count / 3 ) : ( positionAttribute.count / 3 ); - - objects.push( { - object3d: object, - geometry: geometry - } ); - - } - - } ); - - var output; - var offset = 80; // skip header - - if ( binary === true ) { - - var bufferLength = triangles * 2 + triangles * 3 * 4 * 4 + 80 + 4; - var arrayBuffer = new ArrayBuffer( bufferLength ); - output = new DataView( arrayBuffer ); - output.setUint32( offset, triangles, true ); offset += 4; - - } else { - - output = ''; - output += 'solid exported\n'; - - } - - var vA = new Vector3(); - var vB = new Vector3(); - var vC = new Vector3(); - var cb = new Vector3(); - var ab = new Vector3(); - var normal = new Vector3(); - - for ( var i = 0, il = objects.length; i < il; i ++ ) { - - var object = objects[ i ].object3d; - var geometry = objects[ i ].geometry; - - var index = geometry.index; - var positionAttribute = geometry.getAttribute( 'position' ); - - if ( index !== null ) { - - // indexed geometry - - for ( var j = 0; j < index.count; j += 3 ) { - - var a = index.getX( j + 0 ); - var b = index.getX( j + 1 ); - var c = index.getX( j + 2 ); - - writeFace( a, b, c, positionAttribute, object ); - - } - - } else { - - // non-indexed geometry - - for ( var j = 0; j < positionAttribute.count; j += 3 ) { - - var a = j + 0; - var b = j + 1; - var c = j + 2; - - writeFace( a, b, c, positionAttribute, object ); - - } - - } - - } - - if ( binary === false ) { - - output += 'endsolid exported\n'; - - } - - return output; - - function writeFace( a, b, c, positionAttribute, object ) { - - vA.fromBufferAttribute( positionAttribute, a ); - vB.fromBufferAttribute( positionAttribute, b ); - vC.fromBufferAttribute( positionAttribute, c ); - - if ( object.isSkinnedMesh === true ) { - - object.boneTransform( a, vA ); - object.boneTransform( b, vB ); - object.boneTransform( c, vC ); - - } - - vA.applyMatrix4( object.matrixWorld ); - vB.applyMatrix4( object.matrixWorld ); - vC.applyMatrix4( object.matrixWorld ); - - writeNormal( vA, vB, vC ); - - writeVertex( vA ); - writeVertex( vB ); - writeVertex( vC ); - - if ( binary === true ) { - - output.setUint16( offset, 0, true ); offset += 2; - - } else { - - output += '\t\tendloop\n'; - output += '\tendfacet\n'; - - } - - } - - function writeNormal( vA, vB, vC ) { - - cb.subVectors( vC, vB ); - ab.subVectors( vA, vB ); - cb.cross( ab ).normalize(); - - normal.copy( cb ).normalize(); - - if ( binary === true ) { - - output.setFloat32( offset, normal.x, true ); offset += 4; - output.setFloat32( offset, normal.y, true ); offset += 4; - output.setFloat32( offset, normal.z, true ); offset += 4; - - } else { - - output += '\tfacet normal ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n'; - output += '\t\touter loop\n'; - - } - - } - - function writeVertex( vertex ) { - - if ( binary === true ) { - - output.setFloat32( offset, vertex.x, true ); offset += 4; - output.setFloat32( offset, vertex.y, true ); offset += 4; - output.setFloat32( offset, vertex.z, true ); offset += 4; - - } else { - - output += '\t\t\tvertex ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z + '\n'; - - } - - } - - } - -}; - -export { STLExporter }; diff --git a/extlib/TrackballControls.js b/extlib/TrackballControls.js deleted file mode 100644 index d110778..0000000 --- a/extlib/TrackballControls.js +++ /dev/null @@ -1,754 +0,0 @@ -import { - EventDispatcher, - MOUSE, - Quaternion, - Vector2, - Vector3 -} from '../../../build/three.module.js'; - -var TrackballControls = function ( object, domElement ) { - - if ( domElement === undefined ) console.warn( 'THREE.TrackballControls: The second parameter "domElement" is now mandatory.' ); - if ( domElement === document ) console.error( 'THREE.TrackballControls: "document" should not be used as the target "domElement". Please use "renderer.domElement" instead.' ); - - var scope = this; - var STATE = { NONE: - 1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM_PAN: 4 }; - - this.object = object; - this.domElement = domElement; - - // API - - this.enabled = true; - - this.screen = { left: 0, top: 0, width: 0, height: 0 }; - - this.rotateSpeed = 1.0; - this.zoomSpeed = 1.2; - this.panSpeed = 0.3; - - this.noRotate = false; - this.noZoom = false; - this.noPan = false; - - this.staticMoving = false; - this.dynamicDampingFactor = 0.2; - - this.minDistance = 0; - this.maxDistance = Infinity; - - this.keys = [ 65 /*A*/, 83 /*S*/, 68 /*D*/ ]; - - this.mouseButtons = { LEFT: MOUSE.ROTATE, MIDDLE: MOUSE.DOLLY, RIGHT: MOUSE.PAN }; - - // internals - - this.target = new Vector3(); - - var EPS = 0.000001; - - var lastPosition = new Vector3(); - var lastZoom = 1; - - var _state = STATE.NONE, - _keyState = STATE.NONE, - - _eye = new Vector3(), - - _movePrev = new Vector2(), - _moveCurr = new Vector2(), - - _lastAxis = new Vector3(), - _lastAngle = 0, - - _zoomStart = new Vector2(), - _zoomEnd = new Vector2(), - - _touchZoomDistanceStart = 0, - _touchZoomDistanceEnd = 0, - - _panStart = new Vector2(), - _panEnd = new Vector2(); - - // for reset - - this.target0 = this.target.clone(); - this.position0 = this.object.position.clone(); - this.up0 = this.object.up.clone(); - this.zoom0 = this.object.zoom; - - // events - - var changeEvent = { type: 'change' }; - var startEvent = { type: 'start' }; - var endEvent = { type: 'end' }; - - - // methods - - this.handleResize = function () { - - var box = scope.domElement.getBoundingClientRect(); - // adjustments come from similar code in the jquery offset() function - var d = scope.domElement.ownerDocument.documentElement; - scope.screen.left = box.left + window.pageXOffset - d.clientLeft; - scope.screen.top = box.top + window.pageYOffset - d.clientTop; - scope.screen.width = box.width; - scope.screen.height = box.height; - - }; - - var getMouseOnScreen = ( function () { - - var vector = new Vector2(); - - return function getMouseOnScreen( pageX, pageY ) { - - vector.set( - ( pageX - scope.screen.left ) / scope.screen.width, - ( pageY - scope.screen.top ) / scope.screen.height - ); - - return vector; - - }; - - }() ); - - var getMouseOnCircle = ( function () { - - var vector = new Vector2(); - - return function getMouseOnCircle( pageX, pageY ) { - - vector.set( - ( ( pageX - scope.screen.width * 0.5 - scope.screen.left ) / ( scope.screen.width * 0.5 ) ), - ( ( scope.screen.height + 2 * ( scope.screen.top - pageY ) ) / scope.screen.width ) // screen.width intentional - ); - - return vector; - - }; - - }() ); - - this.rotateCamera = ( function () { - - var axis = new Vector3(), - quaternion = new Quaternion(), - eyeDirection = new Vector3(), - objectUpDirection = new Vector3(), - objectSidewaysDirection = new Vector3(), - moveDirection = new Vector3(), - angle; - - return function rotateCamera() { - - moveDirection.set( _moveCurr.x - _movePrev.x, _moveCurr.y - _movePrev.y, 0 ); - angle = moveDirection.length(); - - if ( angle ) { - - _eye.copy( scope.object.position ).sub( scope.target ); - - eyeDirection.copy( _eye ).normalize(); - objectUpDirection.copy( scope.object.up ).normalize(); - objectSidewaysDirection.crossVectors( objectUpDirection, eyeDirection ).normalize(); - - objectUpDirection.setLength( _moveCurr.y - _movePrev.y ); - objectSidewaysDirection.setLength( _moveCurr.x - _movePrev.x ); - - moveDirection.copy( objectUpDirection.add( objectSidewaysDirection ) ); - - axis.crossVectors( moveDirection, _eye ).normalize(); - - angle *= scope.rotateSpeed; - quaternion.setFromAxisAngle( axis, angle ); - - _eye.applyQuaternion( quaternion ); - scope.object.up.applyQuaternion( quaternion ); - - _lastAxis.copy( axis ); - _lastAngle = angle; - - } else if ( ! scope.staticMoving && _lastAngle ) { - - _lastAngle *= Math.sqrt( 1.0 - scope.dynamicDampingFactor ); - _eye.copy( scope.object.position ).sub( scope.target ); - quaternion.setFromAxisAngle( _lastAxis, _lastAngle ); - _eye.applyQuaternion( quaternion ); - scope.object.up.applyQuaternion( quaternion ); - - } - - _movePrev.copy( _moveCurr ); - - }; - - }() ); - - - this.zoomCamera = function () { - - var factor; - - if ( _state === STATE.TOUCH_ZOOM_PAN ) { - - factor = _touchZoomDistanceStart / _touchZoomDistanceEnd; - _touchZoomDistanceStart = _touchZoomDistanceEnd; - - if ( scope.object.isPerspectiveCamera ) { - - _eye.multiplyScalar( factor ); - - } else if ( scope.object.isOrthographicCamera ) { - - scope.object.zoom *= factor; - scope.object.updateProjectionMatrix(); - - } else { - - console.warn( 'THREE.TrackballControls: Unsupported camera type' ); - - } - - } else { - - factor = 1.0 + ( _zoomEnd.y - _zoomStart.y ) * scope.zoomSpeed; - - if ( factor !== 1.0 && factor > 0.0 ) { - - if ( scope.object.isPerspectiveCamera ) { - - _eye.multiplyScalar( factor ); - - } else if ( scope.object.isOrthographicCamera ) { - - scope.object.zoom /= factor; - scope.object.updateProjectionMatrix(); - - } else { - - console.warn( 'THREE.TrackballControls: Unsupported camera type' ); - - } - - } - - if ( scope.staticMoving ) { - - _zoomStart.copy( _zoomEnd ); - - } else { - - _zoomStart.y += ( _zoomEnd.y - _zoomStart.y ) * this.dynamicDampingFactor; - - } - - } - - }; - - this.panCamera = ( function () { - - var mouseChange = new Vector2(), - objectUp = new Vector3(), - pan = new Vector3(); - - return function panCamera() { - - mouseChange.copy( _panEnd ).sub( _panStart ); - - if ( mouseChange.lengthSq() ) { - - if ( scope.object.isOrthographicCamera ) { - - var scale_x = ( scope.object.right - scope.object.left ) / scope.object.zoom / scope.domElement.clientWidth; - var scale_y = ( scope.object.top - scope.object.bottom ) / scope.object.zoom / scope.domElement.clientWidth; - - mouseChange.x *= scale_x; - mouseChange.y *= scale_y; - - } - - mouseChange.multiplyScalar( _eye.length() * scope.panSpeed ); - - pan.copy( _eye ).cross( scope.object.up ).setLength( mouseChange.x ); - pan.add( objectUp.copy( scope.object.up ).setLength( mouseChange.y ) ); - - scope.object.position.add( pan ); - scope.target.add( pan ); - - if ( scope.staticMoving ) { - - _panStart.copy( _panEnd ); - - } else { - - _panStart.add( mouseChange.subVectors( _panEnd, _panStart ).multiplyScalar( scope.dynamicDampingFactor ) ); - - } - - } - - }; - - }() ); - - this.checkDistances = function () { - - if ( ! scope.noZoom || ! scope.noPan ) { - - if ( _eye.lengthSq() > scope.maxDistance * scope.maxDistance ) { - - scope.object.position.addVectors( scope.target, _eye.setLength( scope.maxDistance ) ); - _zoomStart.copy( _zoomEnd ); - - } - - if ( _eye.lengthSq() < scope.minDistance * scope.minDistance ) { - - scope.object.position.addVectors( scope.target, _eye.setLength( scope.minDistance ) ); - _zoomStart.copy( _zoomEnd ); - - } - - } - - }; - - this.update = function () { - - _eye.subVectors( scope.object.position, scope.target ); - - if ( ! scope.noRotate ) { - - scope.rotateCamera(); - - } - - if ( ! scope.noZoom ) { - - scope.zoomCamera(); - - } - - if ( ! scope.noPan ) { - - scope.panCamera(); - - } - - scope.object.position.addVectors( scope.target, _eye ); - - if ( scope.object.isPerspectiveCamera ) { - - scope.checkDistances(); - - scope.object.lookAt( scope.target ); - - if ( lastPosition.distanceToSquared( scope.object.position ) > EPS ) { - - scope.dispatchEvent( changeEvent ); - - lastPosition.copy( scope.object.position ); - - } - - } else if ( scope.object.isOrthographicCamera ) { - - scope.object.lookAt( scope.target ); - - if ( lastPosition.distanceToSquared( scope.object.position ) > EPS || lastZoom !== scope.object.zoom ) { - - scope.dispatchEvent( changeEvent ); - - lastPosition.copy( scope.object.position ); - lastZoom = scope.object.zoom; - - } - - } else { - - console.warn( 'THREE.TrackballControls: Unsupported camera type' ); - - } - - }; - - this.reset = function () { - - _state = STATE.NONE; - _keyState = STATE.NONE; - - scope.target.copy( scope.target0 ); - scope.object.position.copy( scope.position0 ); - scope.object.up.copy( scope.up0 ); - scope.object.zoom = scope.zoom0; - - scope.object.updateProjectionMatrix(); - - _eye.subVectors( scope.object.position, scope.target ); - - scope.object.lookAt( scope.target ); - - scope.dispatchEvent( changeEvent ); - - lastPosition.copy( scope.object.position ); - lastZoom = scope.object.zoom; - - }; - - // listeners - - function onPointerDown( event ) { - - if ( scope.enabled === false ) return; - - switch ( event.pointerType ) { - - case 'mouse': - case 'pen': - onMouseDown( event ); - break; - - // TODO touch - - } - - } - - function onPointerMove( event ) { - - if ( scope.enabled === false ) return; - - switch ( event.pointerType ) { - - case 'mouse': - case 'pen': - onMouseMove( event ); - break; - - // TODO touch - - } - - } - - function onPointerUp( event ) { - - if ( scope.enabled === false ) return; - - switch ( event.pointerType ) { - - case 'mouse': - case 'pen': - onMouseUp( event ); - break; - - // TODO touch - - } - - } - - function keydown( event ) { - - if ( scope.enabled === false ) return; - - window.removeEventListener( 'keydown', keydown ); - - if ( _keyState !== STATE.NONE ) { - - return; - - } else if ( event.keyCode === scope.keys[ STATE.ROTATE ] && ! scope.noRotate ) { - - _keyState = STATE.ROTATE; - - } else if ( event.keyCode === scope.keys[ STATE.ZOOM ] && ! scope.noZoom ) { - - _keyState = STATE.ZOOM; - - } else if ( event.keyCode === scope.keys[ STATE.PAN ] && ! scope.noPan ) { - - _keyState = STATE.PAN; - - } - - } - - function keyup() { - - if ( scope.enabled === false ) return; - - _keyState = STATE.NONE; - - window.addEventListener( 'keydown', keydown ); - - } - - function onMouseDown( event ) { - - event.preventDefault(); - event.stopPropagation(); - - if ( _state === STATE.NONE ) { - - switch ( event.button ) { - - case scope.mouseButtons.LEFT: - _state = STATE.ROTATE; - break; - - case scope.mouseButtons.MIDDLE: - _state = STATE.ZOOM; - break; - - case scope.mouseButtons.RIGHT: - _state = STATE.PAN; - break; - - default: - _state = STATE.NONE; - - } - - } - - var state = ( _keyState !== STATE.NONE ) ? _keyState : _state; - - if ( state === STATE.ROTATE && ! scope.noRotate ) { - - _moveCurr.copy( getMouseOnCircle( event.pageX, event.pageY ) ); - _movePrev.copy( _moveCurr ); - - } else if ( state === STATE.ZOOM && ! scope.noZoom ) { - - _zoomStart.copy( getMouseOnScreen( event.pageX, event.pageY ) ); - _zoomEnd.copy( _zoomStart ); - - } else if ( state === STATE.PAN && ! scope.noPan ) { - - _panStart.copy( getMouseOnScreen( event.pageX, event.pageY ) ); - _panEnd.copy( _panStart ); - - } - - scope.domElement.ownerDocument.addEventListener( 'pointermove', onPointerMove ); - scope.domElement.ownerDocument.addEventListener( 'pointerup', onPointerUp ); - - scope.dispatchEvent( startEvent ); - - } - - function onMouseMove( event ) { - - if ( scope.enabled === false ) return; - - event.preventDefault(); - event.stopPropagation(); - - var state = ( _keyState !== STATE.NONE ) ? _keyState : _state; - - if ( state === STATE.ROTATE && ! scope.noRotate ) { - - _movePrev.copy( _moveCurr ); - _moveCurr.copy( getMouseOnCircle( event.pageX, event.pageY ) ); - - } else if ( state === STATE.ZOOM && ! scope.noZoom ) { - - _zoomEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) ); - - } else if ( state === STATE.PAN && ! scope.noPan ) { - - _panEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) ); - - } - - } - - function onMouseUp( event ) { - - if ( scope.enabled === false ) return; - - event.preventDefault(); - event.stopPropagation(); - - _state = STATE.NONE; - - scope.domElement.ownerDocument.removeEventListener( 'pointermove', onPointerMove ); - scope.domElement.ownerDocument.removeEventListener( 'pointerup', onPointerUp ); - - scope.dispatchEvent( endEvent ); - - } - - function mousewheel( event ) { - - if ( scope.enabled === false ) return; - - if ( scope.noZoom === true ) return; - - event.preventDefault(); - event.stopPropagation(); - - switch ( event.deltaMode ) { - - case 2: - // Zoom in pages - _zoomStart.y -= event.deltaY * 0.025; - break; - - case 1: - // Zoom in lines - _zoomStart.y -= event.deltaY * 0.01; - break; - - default: - // undefined, 0, assume pixels - _zoomStart.y -= event.deltaY * 0.00025; - break; - - } - - scope.dispatchEvent( startEvent ); - scope.dispatchEvent( endEvent ); - - } - - function touchstart( event ) { - - if ( scope.enabled === false ) return; - - event.preventDefault(); - - switch ( event.touches.length ) { - - case 1: - _state = STATE.TOUCH_ROTATE; - _moveCurr.copy( getMouseOnCircle( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) ); - _movePrev.copy( _moveCurr ); - break; - - default: // 2 or more - _state = STATE.TOUCH_ZOOM_PAN; - var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; - var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; - _touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy ); - - var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2; - var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2; - _panStart.copy( getMouseOnScreen( x, y ) ); - _panEnd.copy( _panStart ); - break; - - } - - scope.dispatchEvent( startEvent ); - - } - - function touchmove( event ) { - - if ( scope.enabled === false ) return; - - event.preventDefault(); - event.stopPropagation(); - - switch ( event.touches.length ) { - - case 1: - _movePrev.copy( _moveCurr ); - _moveCurr.copy( getMouseOnCircle( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) ); - break; - - default: // 2 or more - var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX; - var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY; - _touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy ); - - var x = ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX ) / 2; - var y = ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY ) / 2; - _panEnd.copy( getMouseOnScreen( x, y ) ); - break; - - } - - } - - function touchend( event ) { - - if ( scope.enabled === false ) return; - - switch ( event.touches.length ) { - - case 0: - _state = STATE.NONE; - break; - - case 1: - _state = STATE.TOUCH_ROTATE; - _moveCurr.copy( getMouseOnCircle( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ) ); - _movePrev.copy( _moveCurr ); - break; - - } - - scope.dispatchEvent( endEvent ); - - } - - function contextmenu( event ) { - - if ( scope.enabled === false ) return; - - event.preventDefault(); - - } - - this.dispose = function () { - - scope.domElement.removeEventListener( 'contextmenu', contextmenu ); - - scope.domElement.removeEventListener( 'pointerdown', onPointerDown ); - scope.domElement.removeEventListener( 'wheel', mousewheel ); - - scope.domElement.removeEventListener( 'touchstart', touchstart ); - scope.domElement.removeEventListener( 'touchend', touchend ); - scope.domElement.removeEventListener( 'touchmove', touchmove ); - - scope.domElement.ownerDocument.removeEventListener( 'pointermove', onPointerMove ); - scope.domElement.ownerDocument.removeEventListener( 'pointerup', onPointerUp ); - - window.removeEventListener( 'keydown', keydown ); - window.removeEventListener( 'keyup', keyup ); - - }; - - this.domElement.addEventListener( 'contextmenu', contextmenu ); - - this.domElement.addEventListener( 'pointerdown', onPointerDown ); - this.domElement.addEventListener( 'wheel', mousewheel ); - - this.domElement.addEventListener( 'touchstart', touchstart ); - this.domElement.addEventListener( 'touchend', touchend ); - this.domElement.addEventListener( 'touchmove', touchmove ); - - this.domElement.ownerDocument.addEventListener( 'pointermove', onPointerMove ); - this.domElement.ownerDocument.addEventListener( 'pointerup', onPointerUp ); - - window.addEventListener( 'keydown', keydown ); - window.addEventListener( 'keyup', keyup ); - - this.handleResize(); - - // force an update at start - this.update(); - -}; - -TrackballControls.prototype = Object.create( EventDispatcher.prototype ); -TrackballControls.prototype.constructor = TrackballControls; - -export { TrackballControls }; diff --git a/extlib/fs/directory-open.mjs b/extlib/fs/directory-open.mjs deleted file mode 100644 index e51d720..0000000 --- a/extlib/fs/directory-open.mjs +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright 2020 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -// @license © 2020 Google LLC. Licensed under the Apache License, Version 2.0. - -import supported from './supported.mjs'; - -const implementation = !supported - ? import('./legacy/directory-open.mjs') - : supported === 'chooseFileSystemEntries' - ? import('./fs-access-legacy/directory-open.mjs') - : import('./fs-access/directory-open.mjs'); - -/** - * For opening directories, dynamically either loads the File System Access API - * module or the legacy method. - */ -export async function directoryOpen(...args) { - return (await implementation).default(...args); -} diff --git a/extlib/fs/file-open.mjs b/extlib/fs/file-open.mjs deleted file mode 100644 index 407082c..0000000 --- a/extlib/fs/file-open.mjs +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright 2020 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -// @license © 2020 Google LLC. Licensed under the Apache License, Version 2.0. - -import supported from './supported.mjs'; - -const implementation = !supported - ? import('./legacy/file-open.mjs') - : supported === 'chooseFileSystemEntries' - ? import('./fs-access-legacy/file-open.mjs') - : import('./fs-access/file-open.mjs'); - -/** - * For opening files, dynamically either loads the File System Access API module - * or the legacy method. - */ -export async function fileOpen(...args) { - return (await implementation).default(...args); -} diff --git a/extlib/fs/file-save.mjs b/extlib/fs/file-save.mjs deleted file mode 100644 index 8364a05..0000000 --- a/extlib/fs/file-save.mjs +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright 2020 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -// @license © 2020 Google LLC. Licensed under the Apache License, Version 2.0. - -import supported from './supported.mjs'; - -const implementation = !supported - ? import('./legacy/file-save.mjs') - : supported === 'chooseFileSystemEntries' - ? import('./fs-access-legacy/file-save.mjs') - : import('./fs-access/file-save.mjs'); - -/** - * For saving files, dynamically either loads the File System Access API module - * or the legacy method. - */ -export async function fileSave(...args) { - return (await implementation).default(...args); -} diff --git a/extlib/fs/fs-access-legacy/directory-open.mjs b/extlib/fs/fs-access-legacy/directory-open.mjs deleted file mode 100644 index e921f95..0000000 --- a/extlib/fs/fs-access-legacy/directory-open.mjs +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright 2020 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -// @license © 2020 Google LLC. Licensed under the Apache License, Version 2.0. - -const getFiles = async (dirHandle, recursive, path = dirHandle.name) => { - const dirs = []; - const files = []; - for await (const entry of dirHandle.getEntries()) { - const nestedPath = `${path}/${entry.name}`; - if (entry.isFile) { - files.push( - entry.getFile().then((file) => - Object.defineProperty(file, 'webkitRelativePath', { - configurable: true, - enumerable: true, - get: () => nestedPath, - }) - ) - ); - } else if (entry.isDirectory && recursive) { - dirs.push(getFiles(entry, recursive, nestedPath)); - } - } - return [...(await Promise.all(dirs)).flat(), ...(await Promise.all(files))]; -}; - -/** - * Opens a directory from disk using the (legacy) File System Access API. - * @type { typeof import("../../index").directoryOpen } - */ -export default async (options = {}) => { - options.recursive = options.recursive || false; - const handle = await window.chooseFileSystemEntries({ - type: 'open-directory', - }); - return getFiles(handle, options.recursive); -}; diff --git a/extlib/fs/fs-access-legacy/file-open.mjs b/extlib/fs/fs-access-legacy/file-open.mjs deleted file mode 100644 index 2cdfe6b..0000000 --- a/extlib/fs/fs-access-legacy/file-open.mjs +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright 2020 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -// @license © 2020 Google LLC. Licensed under the Apache License, Version 2.0. - -const getFileWithHandle = async (handle) => { - const file = await handle.getFile(); - file.handle = handle; - return file; -}; - -/** - * Opens a file from disk using the (legacy) File System Access API. - * @type { typeof import("../../index").fileOpen } - */ -export default async (options = {}) => { - const handleOrHandles = await window.chooseFileSystemEntries({ - accepts: [ - { - description: options.description || '', - mimeTypes: options.mimeTypes || ['*/*'], - extensions: options.extensions || [''], - }, - ], - multiple: options.multiple || false, - }); - if (options.multiple) { - return Promise.all(handleOrHandles.map(getFileWithHandle)); - } - return getFileWithHandle(handleOrHandles); -}; diff --git a/extlib/fs/fs-access-legacy/file-save.mjs b/extlib/fs/fs-access-legacy/file-save.mjs deleted file mode 100644 index 9fe0ca6..0000000 --- a/extlib/fs/fs-access-legacy/file-save.mjs +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright 2020 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -// @license © 2020 Google LLC. Licensed under the Apache License, Version 2.0. - -/** - * Saves a file to disk using the (legacy) File System Access API. - * @type { typeof import("../../index").fileSave } - */ -export default async (blob, options = {}, handle = null) => { - options.fileName = options.fileName || 'Untitled'; - handle = - handle || - (await window.chooseFileSystemEntries({ - type: 'save-file', - accepts: [ - { - description: options.description || '', - mimeTypes: [blob.type], - extensions: options.extensions || [''], - }, - ], - })); - const writable = await handle.createWritable(); - await writable.write(blob); - await writable.close(); - return handle; -}; diff --git a/extlib/fs/fs-access/directory-open.mjs b/extlib/fs/fs-access/directory-open.mjs deleted file mode 100644 index 19fade2..0000000 --- a/extlib/fs/fs-access/directory-open.mjs +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright 2020 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -// @license © 2020 Google LLC. Licensed under the Apache License, Version 2.0. - -const getFiles = async (dirHandle, recursive, path = dirHandle.name) => { - const dirs = []; - const files = []; - for await (const entry of dirHandle.values()) { - const nestedPath = `${path}/${entry.name}`; - if (entry.kind === 'file') { - files.push( - entry.getFile().then((file) => - Object.defineProperty(file, 'webkitRelativePath', { - configurable: true, - enumerable: true, - get: () => nestedPath, - }) - ) - ); - } else if (entry.kind === 'directory' && recursive) { - dirs.push(getFiles(entry, recursive, nestedPath)); - } - } - return [...(await Promise.all(dirs)).flat(), ...(await Promise.all(files))]; -}; - -/** - * Opens a directory from disk using the File System Access API. - * @type { typeof import("../../index").directoryOpen } - */ -export default async (options = {}) => { - options.recursive = options.recursive || false; - const handle = await window.showDirectoryPicker(); - return getFiles(handle, options.recursive); -}; diff --git a/extlib/fs/fs-access/file-open.mjs b/extlib/fs/fs-access/file-open.mjs deleted file mode 100644 index dab1119..0000000 --- a/extlib/fs/fs-access/file-open.mjs +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Copyright 2020 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -// @license © 2020 Google LLC. Licensed under the Apache License, Version 2.0. - -const getFileWithHandle = async (handle) => { - const file = await handle.getFile(); - file.handle = handle; - return file; -}; - -/** - * Opens a file from disk using the File System Access API. - * @type { typeof import("../../index").fileOpen } - */ -export default async (options = {}) => { - const accept = {}; - if (options.mimeTypes) { - options.mimeTypes.map((mimeType) => { - accept[mimeType] = options.extensions || []; - }); - } else { - accept['*/*'] = options.extensions || []; - } - const handleOrHandles = await window.showOpenFilePicker({ - types: [ - { - description: options.description || '', - accept: accept, - }, - ], - multiple: options.multiple || false, - }); - const files = await Promise.all(handleOrHandles.map(getFileWithHandle)); - if (options.multiple) { - return files; - } - return files[0]; -}; diff --git a/extlib/fs/fs-access/file-save.mjs b/extlib/fs/fs-access/file-save.mjs deleted file mode 100644 index 16b8b2c..0000000 --- a/extlib/fs/fs-access/file-save.mjs +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Copyright 2020 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -// @license © 2020 Google LLC. Licensed under the Apache License, Version 2.0. - -/** - * Saves a file to disk using the File System Access API. - * @type { typeof import("../../index").fileSave } - */ -export default async ( - blob, - options = {}, - existingHandle = null, - throwIfExistingHandleNotGood = false -) => { - options.fileName = options.fileName || 'Untitled'; - const accept = {}; - if (options.mimeTypes) { - options.mimeTypes.push(blob.type); - options.mimeTypes.map((mimeType) => { - accept[mimeType] = options.extensions || []; - }); - } else { - accept[blob.type] = options.extensions || []; - } - if (existingHandle) { - try { - // Check if the file still exists. - await existingHandle.getFile(); - } catch (err) { - existingHandle = null; - if (throwIfExistingHandleNotGood) { - throw err; - } - } - } - const handle = - existingHandle || - (await window.showSaveFilePicker({ - suggestedName: options.fileName, - types: [ - { - description: options.description || '', - accept: accept, - }, - ], - })); - const writable = await handle.createWritable(); - await writable.write(blob); - await writable.close(); - return handle; -}; diff --git a/extlib/fs/index.js b/extlib/fs/index.js deleted file mode 100644 index f67f6df..0000000 --- a/extlib/fs/index.js +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright 2020 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -// @license © 2020 Google LLC. Licensed under the Apache License, Version 2.0. - -/** - * @module browser-fs-access - */ -export { fileOpen } from './file-open.mjs'; -export { directoryOpen } from './directory-open.mjs'; -export { fileSave } from './file-save.mjs'; -export { default as supported } from './supported.mjs'; diff --git a/extlib/fs/legacy/directory-open.mjs b/extlib/fs/legacy/directory-open.mjs deleted file mode 100644 index e58a870..0000000 --- a/extlib/fs/legacy/directory-open.mjs +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Copyright 2020 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -// @license © 2020 Google LLC. Licensed under the Apache License, Version 2.0. - -/** - * Opens a directory from disk using the legacy - * `` method. - * @type { typeof import("../../index").directoryOpen } - */ -export default async (options = {}) => { - options.recursive = options.recursive || false; - return new Promise((resolve, reject) => { - const input = document.createElement('input'); - input.type = 'file'; - input.webkitdirectory = true; - - // ToDo: Remove this workaround once - // https://github.com/whatwg/html/issues/6376 is specified and supported. - const rejectOnPageInteraction = () => { - window.removeEventListener('pointermove', rejectOnPageInteraction); - window.removeEventListener('pointerdown', rejectOnPageInteraction); - window.removeEventListener('keydown', rejectOnPageInteraction); - reject(new DOMException('The user aborted a request.', 'AbortError')); - }; - - window.addEventListener('pointermove', rejectOnPageInteraction); - window.addEventListener('pointerdown', rejectOnPageInteraction); - window.addEventListener('keydown', rejectOnPageInteraction); - - input.addEventListener('change', () => { - window.removeEventListener('pointermove', rejectOnPageInteraction); - window.removeEventListener('pointerdown', rejectOnPageInteraction); - window.removeEventListener('keydown', rejectOnPageInteraction); - let files = Array.from(input.files); - if (!options.recursive) { - files = files.filter((file) => { - return file.webkitRelativePath.split('/').length === 2; - }); - } - resolve(files); - }); - - input.click(); - }); -}; diff --git a/extlib/fs/legacy/file-open.mjs b/extlib/fs/legacy/file-open.mjs deleted file mode 100644 index cfa4f7f..0000000 --- a/extlib/fs/legacy/file-open.mjs +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Copyright 2020 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -// @license © 2020 Google LLC. Licensed under the Apache License, Version 2.0. - -/** - * Opens a file from disk using the legacy `` method. - * @type { typeof import("../../index").fileOpen } - */ -export default async (options = {}) => { - return new Promise((resolve, reject) => { - const input = document.createElement('input'); - input.type = 'file'; - const accept = [ - ...(options.mimeTypes ? options.mimeTypes : []), - options.extensions ? options.extensions : [], - ].join(); - input.multiple = options.multiple || false; - // Empty string allows everything. - input.accept = accept || ''; - - // ToDo: Remove this workaround once - // https://github.com/whatwg/html/issues/6376 is specified and supported. - const rejectOnPageInteraction = () => { - window.removeEventListener('pointermove', rejectOnPageInteraction); - window.removeEventListener('pointerdown', rejectOnPageInteraction); - window.removeEventListener('keydown', rejectOnPageInteraction); - reject(new DOMException('The user aborted a request.', 'AbortError')); - }; - - window.addEventListener('pointermove', rejectOnPageInteraction); - window.addEventListener('pointerdown', rejectOnPageInteraction); - window.addEventListener('keydown', rejectOnPageInteraction); - - input.addEventListener('change', () => { - window.removeEventListener('pointermove', rejectOnPageInteraction); - window.removeEventListener('pointerdown', rejectOnPageInteraction); - window.removeEventListener('keydown', rejectOnPageInteraction); - resolve(input.multiple ? input.files : input.files[0]); - }); - - input.click(); - }); -}; diff --git a/extlib/fs/legacy/file-save.mjs b/extlib/fs/legacy/file-save.mjs deleted file mode 100644 index da453f7..0000000 --- a/extlib/fs/legacy/file-save.mjs +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright 2020 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -// @license © 2020 Google LLC. Licensed under the Apache License, Version 2.0. - -/** - * Saves a file to disk using the legacy `` method. - * @type { typeof import("../../index").fileSave } - */ -export default async (blob, options = {}) => { - const a = document.createElement('a'); - a.download = options.fileName || 'Untitled'; - a.href = URL.createObjectURL(blob); - a.addEventListener('click', () => { - // `setTimeout()` due to - // https://github.com/LLK/scratch-gui/issues/1783#issuecomment-426286393 - setTimeout(() => URL.revokeObjectURL(a.href), 30 * 1000); - }); - a.click(); -}; diff --git a/extlib/fs/supported.mjs b/extlib/fs/supported.mjs deleted file mode 100644 index b1ac42a..0000000 --- a/extlib/fs/supported.mjs +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright 2020 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -// @license © 2020 Google LLC. Licensed under the Apache License, Version 2.0. - -/** - * Returns whether the File System Access API is supported and usable in the - * current context (for example cross-origin iframes). - * @returns {boolean} Returns `true` if the File System Access API is supported and usable, else returns `false`. - */ -const supported = (() => { - // ToDo: Remove this check once Permissions Policy integration - // has happened, tracked in - // https://github.com/WICG/file-system-access/issues/245. - if ('top' in self && self !== top) { - try { - // This will succeed on same-origin iframes, - // but fail on cross-origin iframes. - top.location + ''; - } catch { - return false; - } - } else if ('chooseFileSystemEntries' in self) { - return 'chooseFileSystemEntries'; - } else if ('showOpenFilePicker' in self) { - return 'showOpenFilePicker'; - } - return false; -})(); - -export default supported; diff --git a/extlib/trackball.js b/extlib/trackball.js index ae263f9..f7e000f 100644 --- a/extlib/trackball.js +++ b/extlib/trackball.js @@ -194,7 +194,8 @@ var TrackballControls = function ( object, domElement ) { if ( _state === STATE.TOUCH_ZOOM_PAN ) { - factor = _touchZoomDistanceStart / _touchZoomDistanceEnd; + // factor = _touchZoomDistanceStart / _touchZoomDistanceEnd; + factor = _touchZoomDistanceEnd / _touchZoomDistanceStart; _touchZoomDistanceStart = _touchZoomDistanceEnd; if ( scope.object.isPerspectiveCamera ) {